diff --git a/CMakeLists.txt b/CMakeLists.txt index 41904bffd0f..f7886a817e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -656,6 +656,11 @@ if(FLB_WASM) endif () endif() +# SOME/IP +if(FLB_IN_SOMEIP) + add_subdirectory(${FLB_PATH_LIB_SOMEIP_C} EXCLUDE_FROM_ALL) +endif() + # AWS if (FLB_AWS) FLB_DEFINITION(FLB_HAVE_AWS) diff --git a/cmake/libraries.cmake b/cmake/libraries.cmake index c802f54c07e..9d18d14df38 100644 --- a/cmake/libraries.cmake +++ b/cmake/libraries.cmake @@ -25,3 +25,4 @@ set(FLB_PATH_LIB_SNAPPY "lib/snappy-fef67ac") set(FLB_PATH_LIB_RDKAFKA "lib/librdkafka-2.4.0") set(FLB_PATH_LIB_RING_BUFFER "lib/lwrb") set(FLB_PATH_LIB_WASM_MICRO_RUNTIME "lib/wasm-micro-runtime-WAMR-1.3.3") +set(FLB_PATH_LIB_SOMEIP_C "lib/libsomeip-c") \ No newline at end of file diff --git a/cmake/plugins_options.cmake b/cmake/plugins_options.cmake index b104ebd1f00..6170b06dc07 100644 --- a/cmake/plugins_options.cmake +++ b/cmake/plugins_options.cmake @@ -63,6 +63,7 @@ DEFINE_OPTION(FLB_IN_WINDOWS_EXPORTER_METRICS "Enable windows exporter metrics i DEFINE_OPTION(FLB_IN_WINEVTLOG "Enable Windows EvtLog input plugin" OFF) DEFINE_OPTION(FLB_IN_WINSTAT "Enable Windows Stat input plugin" OFF) DEFINE_OPTION(FLB_IN_EBPF "Enable Linux eBPF input plugin" OFF) +DEFINE_OPTION(FLB_IN_SOMEIP "Enable SOME/IP input plugin" OFF) # Processors # ========== diff --git a/cmake/windows-setup.cmake b/cmake/windows-setup.cmake index 60230408b2e..d3402b214f1 100644 --- a/cmake/windows-setup.cmake +++ b/cmake/windows-setup.cmake @@ -54,6 +54,7 @@ if(FLB_WINDOWS_DEFAULTS) set(FLB_IN_EMITTER Yes) set(FLB_IN_PODMAN_METRICS No) set(FLB_IN_EBPF No) + set(FLB_IN_SOMEIP No) set(FLB_IN_ELASTICSEARCH Yes) set(FLB_IN_SPLUNK Yes) set(FLB_IN_PROMETHEUS_REMOTE_WRITE Yes) diff --git a/conf/in_someip.conf b/conf/in_someip.conf new file mode 100755 index 00000000000..54cac053927 --- /dev/null +++ b/conf/in_someip.conf @@ -0,0 +1,54 @@ +[SERVICE] + # Flush + # ===== + # Set an interval of seconds before to flush records to a destination + Flush 5 + + # Daemon + # ====== + # Instruct Fluent Bit to run in foreground or background mode. + Daemon Off + + # Log_Level + # ========= + # Set the verbosity level of the service, values can be: + # + # - error + # - warning + # - info + # - debug + # - trace + # + # By default 'info' is set, that means it includes 'error' and 'warning'. + Log_Level trace + + # HTTP Monitoring Server + # ====================== + # + # HTTP_Monitor: enable/disable the HTTP Server to monitor + # Fluent Bit internals. + # HTTP_Port : specify the TCP port of the HTTP Server + HTTP_Monitor Off + HTTP_Port 2020 + +[INPUT] + Name someip + Tag in.someip + + # Events to subscribe to. + # Each event should have form: + # Event ,,,,... + # + # Each event must have at least one event group + Event 4,1,32768,1 + Event 4,1,32769,2 + + # RPC to send on startup + # Each RPC entry should have form: + # RPC ,,, + # + # Request payload should be base64 encoded + RPC 4,1,1,CgAQAw== +[OUTPUT] + Name stdout + Match * diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index ae0782ce4a6..caf13f2fe11 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -56,6 +56,9 @@ RUN echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/ flex \ bison \ libyaml-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libboost-filesystem-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -161,6 +164,9 @@ RUN echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/ liblzma5 \ libyaml-0-2 \ libcap2 \ + libboost-system1.74.0 \ + libboost-thread1.74.0 \ + libboost-filesystem1.74.0 \ && \ mkdir -p /dpkg/var/lib/dpkg/status.d/ && \ for deb in *.deb; do \ @@ -247,6 +253,9 @@ RUN echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/ libatomic1 \ libgcrypt20 \ libyaml-0-2 \ + libboost-system1.74.0 \ + libboost-thread1.74.0 \ + libboost-filesystem1.74.0 \ bash gdb valgrind build-essential \ git bash-completion vim tmux jq \ dnsutils iputils-ping iputils-arping iputils-tracepath iputils-clockdiff \ diff --git a/lib/libsomeip-c/CMakeLists.txt b/lib/libsomeip-c/CMakeLists.txt new file mode 100644 index 00000000000..474919f8fec --- /dev/null +++ b/lib/libsomeip-c/CMakeLists.txt @@ -0,0 +1,12 @@ +project(someipc CXX) + +add_subdirectory(vsomeip-3.5.1) + +find_package(vsomeip3 REQUIRED) + +add_library(someip-c SHARED src/someip_wrapper.cc) +target_include_directories(someip-c PUBLIC include) +target_link_libraries(someip-c PRIVATE vsomeip3 vsomeip3-sd vsomeip3-cfg vsomeip3-e2e) +target_link_options(someip-c PUBLIC "-Wl,--disable-new-dtags") + +add_subdirectory(example) \ No newline at end of file diff --git a/lib/libsomeip-c/example/CMakeLists.txt b/lib/libsomeip-c/example/CMakeLists.txt new file mode 100644 index 00000000000..a53713fca39 --- /dev/null +++ b/lib/libsomeip-c/example/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(someip_test_service test_service.c) +target_link_libraries(someip_test_service PRIVATE someip-c) \ No newline at end of file diff --git a/lib/libsomeip-c/example/test_service.c b/lib/libsomeip-c/example/test_service.c new file mode 100644 index 00000000000..016e915a722 --- /dev/null +++ b/lib/libsomeip-c/example/test_service.c @@ -0,0 +1,133 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include "someip_api.h" + + +static const char* NAME = "Test Service"; +static const uint16_t SERVICE_ID = 4; +static const uint16_t INSTANCE_ID = 1; +static const uint16_t METHOD_ID = 1; +static const uint16_t EVENT_ID = 0x8000U; +static const uint16_t EVENT_GROUP_ID = 1; + +static uint16_t client_id = 0; + +/* + * Function to handle callback when a request is received. + * @param request_ptr Pointer to the structure that has the request details. + */ +void HandleRequest(void*, struct some_ip_request *request_ptr) { + static const char* response = "This is the response to the request"; + int ret = 0; + if (request_ptr == NULL) { + return; + } + printf("Received request (method = %d)\n", request_ptr->method_id); + printf("Payload length = %ld\n", request_ptr->payload_len); + + /* Normal service would Parse the request and perform/initiate some actions on it*/ + /* For this example just send back a canned response */ + + ret = someip_send_response(client_id, request_ptr->request_id.client_request_id, + (void*)response, strlen(response)); + if (ret != SOMEIP_RET_SUCCESS) { + printf("Failed to send response: %d\n", ret); + } +} + +/* + * Function to initialize the test service with the SOME/IP library. + * @return 0 on success, -1 on failure. + */ +int Initialize() { + int ret = someip_initialize(NAME, &client_id); + if (ret != SOMEIP_RET_SUCCESS) { + printf("Failed to initialize SOME/IP: %d\n", ret); + return -1; + } + + /* Register Request Handler */ + ret = someip_register_request_handler(client_id, SERVICE_ID, INSTANCE_ID, + METHOD_ID, NULL, HandleRequest); + + if (ret != SOMEIP_RET_SUCCESS) { + printf("Failed to register request handler: %d\n", ret); + someip_shutdown(client_id); + return -1; + } + + /* Offer Event */ + ret = someip_offer_event(client_id, SERVICE_ID, INSTANCE_ID, EVENT_ID, (uint16_t*)&EVENT_GROUP_ID, 1); + if (ret != SOMEIP_RET_SUCCESS) { + printf("Failed to Offer Event: %d\n", ret); + someip_shutdown(client_id); + return -1; + } + + /* Offer Service */ + ret = someip_offer_service(client_id, SERVICE_ID, INSTANCE_ID); + if (ret != SOMEIP_RET_SUCCESS) { + printf("Failed to Offer Service: %d\n", ret); + someip_shutdown(client_id); + return -1; + } + + return 0; +} + +void Teardown() { + someip_shutdown(client_id); +} + +void SendEvent(const int num) { + const char* base_msg = "Event Number "; + char buffer[128]; + int ret = 0; + strcpy(buffer, base_msg); + sprintf(buffer + strlen(base_msg), "%d", num); + + printf("Sending event with message %s\n", buffer); + + ret = someip_send_event(client_id, SERVICE_ID, INSTANCE_ID, EVENT_ID, + buffer, strlen(buffer)); + if (ret != SOMEIP_RET_SUCCESS) { + printf ("Failed to send event, %d\n", ret); + } +} + + +int main() { + int num_events = 10; + if (Initialize() != 0) { + return EXIT_FAILURE; + } + + + for (int i = 0; i <= num_events; ++i) { + SendEvent(i); + sleep(2); + } + + Teardown(); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/lib/libsomeip-c/include/someip_api.h b/lib/libsomeip-c/include/someip_api.h new file mode 100644 index 00000000000..018d3140f75 --- /dev/null +++ b/lib/libsomeip-c/include/someip_api.h @@ -0,0 +1,337 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LIB_SOMEIP_C_SOMEIP_API_H +#define LIB_SOMEIP_C_SOMEIP_API_H +#include "stdint.h" +#include "stddef.h" + +#define SOMEIP_RET_SUCCESS 0 +#define SOMEIP_RET_FAILURE (-1) +#define SOMEIP_RET_NO_EVENT_AVAILABLE (-2) +#define SOMEIP_RET_REQUEST_NOT_FOUND (-3) +#define SOMEIP_RET_SERVICE_NOT_AVAILABLE (-4) + +/* Service available flags */ +#define SOMEIP_SERVICE_NOT_AVAILABLE 0 +#define SOMEIP_SERVICE_AVAILABLE 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * Struct used to hold the data for a received SOME/IP event + */ +struct some_ip_event +{ + /* Service ID */ + uint16_t service_id; + /* Service Instance ID */ + uint16_t instance_id; + /* Event ID (also called Method ID in SOME/IP spec) */ + uint16_t event_id; + /* Length of the Event payload */ + size_t event_len; + /* + * Event Payload contents. + * + * NOTE: Client must free the memory pointed to by event_data if it is not NULL + * after consuming the event. + */ + uint8_t *event_data; +}; + +/* + * Structure used to encapsulate the data to fully identify a RPC request + */ +struct some_ip_request_id +{ + /* Service ID */ + uint16_t service_id; + + /* Service Instance ID */ + uint16_t instance_id; + + /* + * Request Identifier + * + * This is assigned by the someip-c library when a request has be sent successfully + */ + uint32_t client_request_id; +}; + +/* + * Structure used to encapsulate a SOME/IP Request + */ +struct some_ip_request +{ + + /* + * Data needed to identify the request + * + * Note: When sending the request, the client need not populate the client_request_id + * field in the request_id. The someip-c library will assign it when the RPC + * request is sent. + */ + struct some_ip_request_id request_id; + + /* Method ID */ + uint16_t method_id; + + /* Length of the request payload */ + size_t payload_len; + /* Request Payload contents */ + uint8_t *payload; +}; + +/* + * Structure used to store a SOME/IP response + */ +struct some_ip_response +{ + /* Data needed to identify the request */ + struct some_ip_request_id request_id; + /* Method ID */ + uint16_t method_id; + /* Length of the response payload */ + size_t payload_len; + /* + * Response Payload contents + * + * NOTE: Client needs to free the payload memory after consuming the response + */ + uint8_t *payload; +}; + +/* + * Initializes use of the SOME/IP library for an application + * + * @param app_name C-string (null terminated) name of application using SOME/IP library + * @param client_id Pointer to store the unique client identifier for this user of the library + * + * @return SOMEIP_RET_SUCCESS on success, SOMEIP_RET_FAILURE on failure + */ +int someip_initialize(const char *app_name, uint16_t * client_id); + +/* + * Shuts down the SOME/IP library for the specified application + * + * @param client_id Application client identifier + * + */ +void someip_shutdown(uint16_t client_id); + +/* + * Function to access a received event notification + * + * This function can either be polled, or called after the notify_cb is called to indicate + * a SOME/IP event has been received. + * + * @param client_id Application client identifier + * @param event_ptr Pointer to a structure to store the event data. Must be non-NULL. + * + * @return SOMEIP_RET_SUCCESS if event_ptr is populated; + * SOMEIP_RET_NO_EVENT_AVAILABLE indicates there are no more events to retrieve + * SOMEIP_RET_FAILURE if there is an internal failure retrieving the event + */ +int someip_get_next_event(uint16_t client_id, + struct some_ip_event *event_ptr); + +/* + * Function to subscribe for a SOME/IP event + * + * @param client_id Application client identifier + * @param service Service ID + * @param instance Service instance ID + * @param event Event ID + * @param cookie Pointer that is passed back to client in the notify_cb + * @param notify_cb Optional call back function to notify the client an event + * notification has been received. + * + * @return SOMEIP_RET_SUCCESS on success, SOMEIP_RET_FAILURE on failure + */ +int someip_subscribe_event(uint16_t client_id, uint16_t service, + uint16_t instance, uint16_t event, + uint16_t event_groups[], + size_t num_event_groups, void *cookie, + void (*notify_cb)(void *)); + +/* + * Function to request a SOME/IP service + * + * @param client_id Application client identifier + * @param service Identifier + * @param instance Service instance identifier + * @param cookie Passed back to client in the avail_cb + * @param avail_cb Callback to notify the client if the service is available or not. + * Besides the cookie, the service, instance, and availability flag + * (either SOMEIP_SERVICE_NOT_AVAILABLE or SOMEIP_SERVICE_AVAILABLE) is + * supplied in the callback. + */ +int someip_request_service(uint16_t client_id, uint16_t service, + uint16_t instance, void *cookie, + void (*avail_cb)(void *, uint16_t, uint16_t, + int)); + +/* + * RPC Requests + * + * Each RPC request has an identifier assigned to it. However, the request identifier + * is only unique within a transaction with a given {service, instance}. + * + * When initiating a request the client will provide the following: + * 1. Service ID + * 2. Instance ID + * 3. Method ID of the RPC + * 4. Payload that goes into the request + * + * If someip-c is able to successfully send the request, it will provide the request + * identifier to the client. + * + * When a response is received for the request, someip-c will call the response_cb, + * passing back the {service ID, instance ID, request ID} tuple to identify the request + * + */ + +/* + * Send a SOME/IP request + * + * A request can only be sent to the service if it is available. A client can + * track the availability of the service via the someip_request_service and + * providing an avail_cb. Or it can re-attempt the RPC at a later time if + * SOMEIP_RET_SERVICE_NOT_AVAILABLE is returned. + * + * @param client_id Application client identifier + * @param parameters Request parameters. On success the request_id will be + * populated with a unique identifier for this request. + * The payload of the request can be safely de-allocated if + * necessary after return from this method. + * @param cookie Pointer that is passed back to client in the response_cb + * @param response_cb Callback invoked when a response is received. The cookie and + * request identifier are passed as arguments in the callback. + * + * @return SOMEIP_RET_SUCCESS if event_ptr is populated; + * SOMEIP_RET_SERVICE_NOT_AVAILABLE if the service is not available + * SOMEIP_RET_FAILURE if there is an internal failure + */ +int someip_send_request(uint16_t client_id, + struct some_ip_request *parameters, void *cookie, + void (*response_cb)(void *, + const struct + some_ip_request_id *)); + +/* + * Retrieve a SOME/IP response + * + * @param client_id Application client identifier + * @param response Pointer to struct that has the request information. The someip-c + * library will populate the response payload in the structure. + * + * @return SOMEIP_RET_SUCCESS if event_ptr is populated; + * SOMEIP_RET_REQUEST_NOT_FOUND if a response for the request_id is not found + * SOMEIP_RET_FAILURE if there is an internal failure + */ +int someip_get_response(uint16_t client_id, + struct some_ip_response *response); + +/* + * Function to offer a SOME/IP event + * + * @param client_id Application client identifier + * @param service Service ID + * @param instance Service instance ID + * @param event Event ID + * @param event_groups Array of event groups this event belongs to + * @param num_event_groups Number of event groups in the array + * + * @return SOMEIP_RET_SUCCESS on success, SOMEIP_RET_FAILURE on failure + */ +int someip_offer_event(uint16_t client_id, uint16_t service, + uint16_t instance, uint16_t event, + uint16_t event_groups[], size_t num_event_groups); + +/* + * Function to offer a SOME/IP service + * + * @param client_id Application client identifier + * @param service Service ID + * @param instance Service instance ID + * + * @return SOMEIP_RET_SUCCESS on success, SOMEIP_RET_FAILURE on failure + */ +int someip_offer_service(uint16_t client_id, uint16_t service, + uint16_t instance); + +/* + * Send/Publish an Event + * + * @param client_id Application client identifier + * @param service Identifier + * @param instance Service instance ID + * @param event Event identifier + * @param payload Pointer to bytes to send in event payload + * @param payload_size Size of event payload + * + * @return SOMEIP_RET_SUCCESS If event is published successfully + * SOMEIP_RET_FAILURE if there is an internal failure + */ +int someip_send_event(uint16_t client_id, uint16_t service, + uint16_t instance, uint16_t event, + const void *payload, uint32_t payload_size); + +/* + * Registers a request handler for incoming requests for the specified + * SOME/IP method. + * + * @param client_id Application client identifier + * @param service Identifier + * @param instance Service instance ID + * @param method SOME/IP method + * @param request_cb Callback function used to deliver request to client. + * Note: The structure passed as an argument is owned + * by the library. It does not need to be freed by the + * client. The structure will be destroyed upon + * return from the callback. + * + */ +int someip_register_request_handler(uint16_t client_id, uint16_t service, + uint16_t instance, uint16_t method, + void *cookie, + void (*request_cb)(void*, struct + some_ip_request + *)); + +/* + * Function to send an RPC response + * + * @param client_id Application client identifier + * @param request_id The unique SOME/IP identifier for the request that + * we are responding to + * @param payload Pointer to the response payload + * @param payload_size Size of the response payload + */ +int someip_send_response(uint16_t client_id, uint32_t request_id, + void *payload, uint32_t payload_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libsomeip-c/src/someip_wrapper.cc b/lib/libsomeip-c/src/someip_wrapper.cc new file mode 100644 index 00000000000..cc6e602e3ec --- /dev/null +++ b/lib/libsomeip-c/src/someip_wrapper.cc @@ -0,0 +1,864 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "someip_api.h" + +namespace { + /** + * Method used to retrieve the SOME/IP library mutex + * + * This mutex should be held when accessing/modifying the following: + * + * - Map of application client contexts + * + * @return Mutex instance + */ + std::mutex& someip_mutex() { + static std::mutex the_mutex; + return the_mutex; + } + + /** + * Encapsulates a specific SOME/IP application context + */ + class SomeIpContext { + public: + /** + * Encapsulates a service instance + */ + struct Service { + vsomeip::service_t service_id; /* Service identifier */ + vsomeip::instance_t instance_id; /* Service instance */ + + bool operator==(const Service& other) const { + return service_id == other.service_id && instance_id == other.instance_id; + } + + bool operator<(const Service& other) const { + if ((service_id < other.service_id) || + (service_id == other.service_id && instance_id < other.instance_id)) { + return true; + } + return false; + } + }; + + /** + * Encapsulates a SOME/IP method + */ + struct Method { + Service service; + vsomeip::method_t method_id; + + bool operator==(const Method& other) const { + return service == other.service && method_id == other.method_id; + } + + bool operator<(const Method& other) const { + if ((service < other.service) || + (service == other.service && method_id < other.method_id)) { + return true; + } + return false; + } + }; + + /* + * Encapsulates a SOME/IP event + */ + struct Event { + Service service; + vsomeip::event_t event_id; + }; + + using NotifyHandler = std::function; + using ResponseHandler = std::function; + using AvailabilityHandler = std::function; + using RequestHandler = std::function; + + /** + * Constructor + * @param app Vsomeip application instance for this context + */ + explicit SomeIpContext(std::shared_ptr app) : + application_(std::move(app)) { + } + + /** + * Starts the SOME/IP context + */ + void Start() { + // Launch a thread that calls the start method on the application + // Local mutex used to sync between this thread and the start thread + std::mutex start_mutex; + + // Used by the start thread to indicated to this thread it has been started + std::condition_variable start_thread_executing; + auto thread_running{false}; + + // Start up event handling thread + auto app = application_; + auto run{ + [&start_thread_executing, &thread_running, &start_mutex, + app_copy = app] { + // start() blocks, so notify the calling thread that we started + // executing + { + std::lock_guard local_lock{start_mutex}; + thread_running = true; + start_thread_executing.notify_all(); + } + // Blocks until application->stop() has been called + app_copy->start(); + }}; + + // Launch the thread that blocks on start(); + start_future_ = std::async(std::launch::async, run); + + // Wait until the start thread has started executing + std::unique_lock start_lock{start_mutex}; + start_thread_executing.wait(start_lock, [&thread_running] { + return thread_running; + }); + } + + /** + * Shuts down the SOME/IP context + */ + void Shutdown() { + std::lock_guard lock{context_mutex_}; + if (application_) { + // Call stop and wait for the start thread to exit + application_->stop(); + start_future_.wait(); + application_.reset(); + } + } + + /** + * Retrieves the next event + * @param event_ptr Pointer to structure to populate with the event data + * @return SOMEIP_RET_SUCCESS if event is availble and structure is populated + * SOMEIP_RET_NO_EVENT_AVAILABLE if there is no more events + */ + int GetNextEvent(some_ip_event* event_ptr) { + std::shared_ptr message; + { + std::lock_guard lock{context_mutex_}; + if (!event_queue_.empty()) { + message = event_queue_.front(); + event_queue_.pop(); + } + } + + if (!message) { + return SOMEIP_RET_NO_EVENT_AVAILABLE; + } + + auto&& payload{message->get_payload()}; + event_ptr->service_id = message->get_service(); + event_ptr->instance_id = message->get_instance(); + event_ptr->event_id = message->get_method(); + event_ptr->event_len = payload->get_length(); + if (event_ptr->event_len > 0) { + event_ptr->event_data = + (uint8_t*)malloc(event_ptr->event_len); + if (event_ptr->event_data == nullptr) { + return SOMEIP_RET_FAILURE; + } + std::copy(payload->get_data(), + payload->get_data() + payload->get_length(), + event_ptr->event_data); + } + else { + event_ptr->event_data = nullptr; + } + + return SOMEIP_RET_SUCCESS; + } + + /** + * Subscribes for an event + * + * @param event Event details + * @param groups Event groups the event belongs in + * @param handler Callback for delivering received notifications for the event + */ + void SubscribeForEvent(const Event& event, + const std::set& groups, + NotifyHandler handler) { + std::lock_guard lock{context_mutex_}; + // Register message handler for the event + auto message_handler{ + [this, handler = + std::move(handler)](const std::shared_ptr< + vsomeip::message>& message) { + { + std::cout << "Received message for service " << message->get_service() << " event = " << message->get_method() << std::endl; + std::lock_guard lock{context_mutex_}; + event_queue_.push(message); + } + handler(); + }}; + application_->register_message_handler(event.service.service_id, event.service.instance_id, + event.event_id, std::move(message_handler)); + application_->request_event(event.service.service_id, event.service.instance_id, + event.event_id, groups); + for (auto&& event_group : groups) { + application_->subscribe(event.service.service_id, + event.service.instance_id, + event_group); + } + + // Make sure we have requested this service + CheckAndRequestService(event.service); + } + + /** + * Request a service from the SOME/IP stack + * @param service Service details + * @param cb Callback used to inform when service is/is not available + */ + void RequestService(const Service& service, + AvailabilityHandler cb) { + std::lock_guard lock(context_mutex_); + CheckAndRequestService(service); + availability_handlers_[service].emplace_back(std::move(cb)); + } + + /** + * Send a request through the SOME/IP stack + * @param parameters Pointer to struct with the request details + * @param response_handler Used to deliver a response back to the requestor + * @return SOMEIP_RET_SERVICE_NOT_AVAILABLE if the service is currently not available + * SOMEIP_RET_SUCCESS if the request is sent out successfully + */ + int SendRequest(some_ip_request* parameters, + ResponseHandler response_handler) { + std::lock_guard lock(context_mutex_); + // Make sure we have requested the service + const Service service{ + parameters->request_id.service_id, + parameters->request_id.instance_id}; + + CheckAndRequestService(service); + + // There really is no need to send request if the service is not available + // yet. Fail and let the client retry + if (!requested_services_[service]) { + return SOMEIP_RET_SERVICE_NOT_AVAILABLE; + } + + // We can't have a single handler for the response (unfortunately) we need to + // register a handler just for this method + const Method method{ + service, + parameters->method_id}; + auto&& method_entry(registered_methods_.find(method)); + if (method_entry == registered_methods_.end()) { + auto method_message_handler{ + [this](const std::shared_ptr& message) { + HandleResponse(message); + }}; + application_->register_message_handler(service.service_id, + service.instance_id, + method.method_id, + std::move(method_message_handler)); + } + + auto request{vsomeip::runtime::get()->create_request()}; + request->set_service(service.service_id); + request->set_instance(service.instance_id); + request->set_method(method.method_id); + if (!response_handler) { + // No response callback specified. Setting message type to fire and forget. + request->set_message_type(vsomeip_v3::message_type_e:: + MT_REQUEST_NO_RETURN); + } + + auto request_payload{ + vsomeip::runtime::get()->create_payload(parameters->payload, + parameters->payload_len)}; + request->set_payload(request_payload); + application_->send(request); + parameters->request_id.client_request_id = + request->get_request(); + if (response_handler) { + auto&& service_map{pending_requests_[service]}; + service_map[parameters->request_id.client_request_id] = + std::move(response_handler); + } + return SOMEIP_RET_SUCCESS; + } + + /** + * Retrieve a received SOME/IP response + * @param response_ptr Pointer to structure to store the response + * @return SOMEIP_RET_SUCCESS if the response is stored successfully + * SOMEIP_RET_REQUEST_NOT_FOUND if the response is not found for the specified request + * SOMEIP_RET_FAILURE if there is a general error in creating the response + */ + int GetResponse(some_ip_response* response_ptr) { + std::lock_guard lock(context_mutex_); + // See if we can find the response + const Service service{ + response_ptr->request_id.service_id, + response_ptr->request_id.instance_id}; + auto&& service_response_entry{responses_.find(service)}; + if (service_response_entry == responses_.end()) { + return SOMEIP_RET_REQUEST_NOT_FOUND; + } + + auto&& service_responses(service_response_entry->second); + auto&& request_entry(service_responses.find(response_ptr->request_id.client_request_id)); + if (request_entry == service_responses.end()) { + return SOMEIP_RET_REQUEST_NOT_FOUND; + } + + auto&& response_message(request_entry->second); + auto&& payload(response_message->get_payload()); + response_ptr->payload_len = payload->get_length(); + if (response_ptr->payload_len > 0) { + response_ptr->payload = + (uint8_t*)malloc(response_ptr->payload_len); + if (response_ptr->payload == nullptr) { + return SOMEIP_RET_FAILURE; + } + std::copy(payload->get_data(), + payload->get_data() + payload->get_length(), + response_ptr->payload); + } + else { + response_ptr->payload = nullptr; + } + + // Clean up + service_responses.erase(request_entry); + if (service_responses.empty()) { + responses_.erase(service_response_entry); + } + return SOMEIP_RET_SUCCESS; + } + + /** + * Function to offer an event over the SOME/IP stack + * @param event Event details + * @param event_groups Event groups the event belongs to + */ + void OfferEvent(const Event& event, + const std::set& event_groups) { + std::lock_guard lock(context_mutex_); + application_->offer_event(event.service.service_id, + event.service.instance_id, + event.event_id, event_groups); + } + + /** + * Offer a SOME/IP service + * @param service Service details + */ + void OfferService(const Service& service) { + std::lock_guard lock{context_mutex_}; + application_->offer_service(service.service_id, + service.instance_id); + } + + /** + * Sends a notification for a SOME/IP event + * @param event Event identifier + * @param payload Holds the payload to put in the notification + */ + void SendNotification(const Event& event, + std::shared_ptr payload) { + std::lock_guard lock(context_mutex_); + application_->notify(event.service.service_id, + event.service.instance_id, + event.event_id, payload, true); + std::cout << "Sent notification for service " << event.service.service_id << ", event " << event.event_id << std::endl; + } + + /** + * Add a handler for a SOME/IP method + * @param method Method identifier + * @param handler Callback to use when a request is received + */ + void AddRequestHandler(const Method& method, + RequestHandler handler) { + auto message_handler{ + [this, handler = + std::move(handler)](const std::shared_ptr& message) { + // Create the pending response + const auto request_id{message->get_request()}; + auto pending_response{::vsomeip::runtime::get()->create_response(message)}; + { + std::lock_guard callback_lock{context_mutex_}; + pending_responses_[request_id] = + std::move(pending_response); + } + auto payload(message->get_payload()); + uint8_t* payload_bytes{nullptr}; + uint32_t payload_size{0}; + if (payload && payload->get_length() > 0) { + payload_bytes = payload->get_data(); + payload_size = payload->get_length(); + } + handler(request_id, payload_bytes, payload_size); + }}; + std::lock_guard lock(context_mutex_); + application_->register_message_handler(method.service.service_id, + method.service.instance_id, + method.method_id, + std::move(message_handler)); + } + + /** + * Send a SOME/IP response + * @param request_id Identifies the request this response is for + * @param payload Payload to put into the response + */ + void SendResponse(const uint32_t request_id, + const std::vector& payload) { + std::lock_guard lock(context_mutex_); + auto&& pending_response(pending_responses_.find(request_id)); + if (pending_response == pending_responses_.end()) { + return; + } + auto response_message(pending_response->second); + auto response_payload(vsomeip::runtime::get()->create_payload(payload)); + response_message->set_payload(response_payload); + application_->send(response_message); + pending_responses_.erase(pending_response); + } + + private: + /* vSomeIp application associated with this context */ + std::shared_ptr application_; + + /* Mutex to protect access to the class members between vSomeIp threads and client threads */ + std::mutex context_mutex_; + + /* Holds the future when the application is running */ + std::future start_future_; + + /* Used to hold received events until client retrieves them */ + std::queue> event_queue_; + + /* Tracks the services this context has requested. The value is a flag to track if the service is available */ + std::map requested_services_; + + /* Maps of service and registered availability handler */ + std::map> availability_handlers_; + + /* Registered methods */ + std::set registered_methods_; + + /* Map that holds response handlers for pending requests */ + std::map> pending_requests_; + + /* Map that holds received responses until retrieved from the client */ + std::map>> responses_; + + /* Map used to hold received requests until the client application sends a response */ + std::map> pending_responses_; + + /** + * Function to check if the specified service instance has been requested. If it + * hasn't been requested, then request it and add to the requested service list. + * + * @param Service SOME/IP Service + */ + void CheckAndRequestService(const Service& service) { + auto&& service_entry{requested_services_.find(service)}; + if (service_entry == requested_services_.end()) { + // Handler called by vsomeip to inform of service availability + auto availability_handler{ + [this](vsomeip::service_t service_id, + vsomeip::instance_t instance_id, + const bool avail) { + // Need to let any registered clients of the service availability + std::vector to_inform; + const Service service{service_id, instance_id}; + std::unique_lock avail_lock(context_mutex_); + requested_services_[service] = avail; + auto&& service_entry{availability_handlers_.find(service)}; + if (service_entry == availability_handlers_.end()) { + return; + } + to_inform = service_entry->second; + avail_lock.unlock(); + for (auto&& client : to_inform) { + client(avail); + } + }}; + application_->register_availability_handler(service.service_id, + service.instance_id, + std::move(availability_handler)); + application_->request_service(service.service_id, + service.instance_id); + requested_services_[service] = false; + } + } + + /** + * Function to process a RPC response message + * @param message Message (from vsomeip) with RPC response + */ + void HandleResponse(const std::shared_ptr& message) { + const Service service{message->get_service(), message->get_instance()}; + const auto request_id{message->get_request()}; + std::unique_lock response_lock{context_mutex_}; + // Find the pending request + auto&& service_requests_entry{pending_requests_.find(service)}; + if (service_requests_entry == pending_requests_.end()) { + return; + } + auto&& service_requests{service_requests_entry->second}; + auto&& request_entry{service_requests.find(request_id)}; + if (request_entry == service_requests.end()) { + return; + } + + // Pull out the callback to inform the client that a response was received + auto handler{std::move(request_entry->second)}; + + // Clean up the entry for this specific request + service_requests.erase(request_entry); + + // Clean up the service entry to the pending map if there are no more requests + // for that specific service + if (service_requests.empty()) { + pending_requests_.erase(service_requests_entry); + } + + // Add the response message to the cached responses + auto&& service_entry{responses_[service]}; + service_entry[request_id] = message; + response_lock.unlock(); + // Inform the client that the response was received + handler(request_id); + } + }; + + /** + * @return The map of SOME/IP contexts + */ + std::map>& context_map() { + static std::map> map; + return map; + } + +} // namespace + +int someip_initialize(const char* app_name, + uint16_t* client_id) { + if (client_id == nullptr) { + return SOMEIP_RET_FAILURE; + } + auto application{::vsomeip::runtime::get()->create_application(app_name)}; + if (!application || !application->init()) { + application.reset(); + return SOMEIP_RET_FAILURE; + } + + // Create the application context + auto app_context{std::make_shared(application)}; + app_context->Start(); + // Record the client_id + *client_id = application->get_client(); + // Save off the context + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + contexts.emplace(*client_id, app_context); + return SOMEIP_RET_SUCCESS; +} + +void someip_shutdown(const uint16_t client_id) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context{contexts.find(client_id)}; + if (context != contexts.end()) { + context->second->Shutdown(); + } + contexts.erase(context); +} + +int someip_get_next_event(const uint16_t client_id, + some_ip_event* event_ptr) { + // Validate the input parameter + if (event_ptr == nullptr) { + return SOMEIP_RET_FAILURE; + } + + // Get the context + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + return context_entry->second->GetNextEvent(event_ptr); +} + +int someip_subscribe_event(uint16_t client_id, + uint16_t service, + uint16_t instance, + uint16_t event, + uint16_t event_groups[], + size_t num_event_groups, + void* cookie, + void (*notify_cb)(void*)) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + if (event_groups == nullptr) { + return SOMEIP_RET_FAILURE; + } + + std::set groups; + for (auto i = 0; i < num_event_groups; ++i) { + groups.insert(event_groups[i]); + } + + auto notify_handler{[cookie, notify_cb]() { + notify_cb(cookie); + }}; + context_entry->second->SubscribeForEvent( + {{service, instance}, + event}, + groups, std::move(notify_handler)); + return SOMEIP_RET_SUCCESS; +} + +int someip_request_service(uint16_t client_id, + uint16_t service, uint16_t instance, void* cookie, + void (*avail_cb)(void*, uint16_t, uint16_t, int)) { + std::lock_guard request_serv_lock(someip_mutex()); + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + auto client_cb{[service, instance, cookie, avail_cb](const bool available) { + if (avail_cb == nullptr) { + return; + } + const auto avail_flag{available ? SOMEIP_SERVICE_AVAILABLE : SOMEIP_SERVICE_NOT_AVAILABLE}; + avail_cb(cookie, service, instance, avail_flag); + }}; + context_entry->second->RequestService({service, instance}, + std::move(client_cb)); + return SOMEIP_RET_SUCCESS; +} + +int someip_send_request(uint16_t client_id, struct some_ip_request* parameters, + void* cookie, + void (*response_cb)(void*, const struct some_ip_request_id*)) { + // Check the parameters + if (parameters == nullptr) { + return SOMEIP_RET_FAILURE; + } + + if (parameters->payload_len > 0 && parameters->payload == nullptr) { + return SOMEIP_RET_FAILURE; + } + + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + SomeIpContext::ResponseHandler response_handler; + if (response_cb != nullptr) { + response_handler = + {[cookie, response_cb, + request_id = + parameters->request_id](const uint32_t + client_request) mutable { + + request_id. + client_request_id = + client_request; + response_cb(cookie, + &request_id); }}; + } + return context_entry->second->SendRequest(parameters, + std::move(response_handler)); +} + +int someip_get_response(uint16_t client_id, + struct some_ip_response* response) { + // Check the parameters + if (response == nullptr) { + return SOMEIP_RET_FAILURE; + } + + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + return context_entry->second->GetResponse(response); +} + +int someip_offer_event(uint16_t client_id, + uint16_t service, + uint16_t instance, + uint16_t event, + uint16_t event_groups[], + size_t num_event_grps) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + if (event_groups == NULL) { + return SOMEIP_RET_FAILURE; + } + + std::set groups; + for (auto i = 0; i < num_event_grps; ++i) { + groups.insert(event_groups[i]); + } + + context_entry->second->OfferEvent({{service, + instance}, + event}, + groups); + return SOMEIP_RET_SUCCESS; +} + +int someip_offer_service(uint16_t client_id, + uint16_t service, + uint16_t instance) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + context_entry->second->OfferService({service, + instance}); + return SOMEIP_RET_SUCCESS; +} + +int someip_send_event(uint16_t client_id, + uint16_t service, + uint16_t instance, + uint16_t event, + const void* payload_ptr, + uint32_t payload_size) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + std::shared_ptr payload; + auto runtime{vsomeip::runtime::get()}; + if (payload_ptr != nullptr && + payload_size > 0) { + payload = runtime->create_payload(static_cast(payload_ptr), + payload_size); + } + else { + payload = runtime->create_payload(); + } + + context_entry->second->SendNotification({{service, + instance}, + event}, + payload); + return SOMEIP_RET_SUCCESS; +} + +int someip_register_request_handler(uint16_t client_id, + uint16_t service, + uint16_t instance, + uint16_t method, + void* cookie, + void (*request_cb)(void*, struct + some_ip_request*)) { + std::lock_guardlock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + if (request_cb == nullptr) { + return SOMEIP_RET_FAILURE; + } + + auto request_handler{[request_cb, service, instance, method, cookie] + (const uint32_t request_id, uint8_t* payload_ptr, const uint32_t payload_size) { + struct some_ip_request request {{service, instance, request_id}, + method, payload_size, payload_ptr}; + request_cb(cookie, &request); + } + }; + context_entry->second->AddRequestHandler({{service, + instance}, + method}, + std:: + move(request_handler)); + return SOMEIP_RET_SUCCESS; +} + +int someip_send_response(uint16_t client_id, uint32_t request_id, + void* payload, uint32_t payload_len) { + std::lock_guard lock{someip_mutex()}; + auto&& contexts{context_map()}; + auto&& context_entry{contexts.find(client_id)}; + if (context_entry == contexts.end()) { + return SOMEIP_RET_FAILURE; + } + + std::vector payload_buffer; + if (payload != nullptr && payload_len > 0) { + payload_buffer.resize(payload_len); + std::memcpy(payload_buffer.data(), (uint8_t*)payload, payload_len); + } + + context_entry->second->SendResponse(request_id, + payload_buffer); + return SOMEIP_RET_SUCCESS; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/bug-report.yaml b/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/bug-report.yaml new file mode 100644 index 00000000000..32cbb84d773 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -0,0 +1,56 @@ +name: Bug Report +description: Create a report to help us improve +title: "[BUG]: " +labels: bug +body: + - type: input + id: version + attributes: + label: vSomeip Version + placeholder: "v3.4.10" + description: "*or hash of the latest commit used" + validations: + required: true + - type: input + id: boost + attributes: + label: Boost Version + placeholder: "1.71" + validations: + required: true + - type: input + id: environment + attributes: + label: Environment + placeholder: "Windows 11, Ubuntu 22.04, Embedded Linux, QNX, ..." + description: "*or compiler used" + validations: + required: true + - type: textarea + id: description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction Steps + description: Steps to reproduce the behavior + validations: + required: false + - type: textarea + id: expected + attributes: + label: Expected behaviour + description: A clear and concise description of what you expected to happen + validations: + required: false + - type: textarea + id: screenshots + attributes: + label: Logs and Screenshots + description: If applicable, add logs and screenshots to help explain your problem. + validations: + required: false diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/config.yml b/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..3ba13e0cec6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.github/workflows/c-cpp.yml b/lib/libsomeip-c/vsomeip-3.5.1/.github/workflows/c-cpp.yml new file mode 100644 index 00000000000..16983637f2d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.github/workflows/c-cpp.yml @@ -0,0 +1,68 @@ +name: C/C++ CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build_on_ubuntu_boost_183_gcc_x86: + runs-on: ubuntu-latest + steps: + - name: Ubuntu - Install boost 1.83.0 with gcc and x86 + uses: MarkusJx/install-boost@v2.4.4 + id: ubuntu-gcc-1_83-x86 + with: + boost_version: 1.83.0 + platform_version: 20.04 + boost_install_dir: /home/runner + toolset: gcc + arch: x86 + cache: true + + - uses: actions/checkout@v4 + + - name: install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y googletest asciidoc source-highlight doxygen graphviz libbenchmark-dev + + - name: Run CMake config + run: cmake -Bbuild -DBOOST_ROOT=/home/runner/boost/boost/ -DGTEST_ROOT=/usr/src/googletest + + - name: Build CMake + run: cmake --build build --target build_tests + + - name: Run Unit tests + run: ctest --test-dir build --tests-regex '^unit_' --verbose + + - name: Run BenchMark tests + run: env -C build test/benchmark_tests/benchmark_tests_bin + + - uses: actions/upload-artifact@v4 + with: + name: vsomeip + path: "${{ runner.workspace }}/install/**/*" + + build_on_windows_boost_183_gcc_x86: + runs-on: windows-latest + steps: + - name: Windows - Install boost 1.83.0 with gcc and x86 + uses: MarkusJx/install-boost@v2.4.4 + id: windows-gcc-1_83-x86 + with: + boost_version: 1.83.0 + platform: windows + boost_install_dir: C:\runner + toolset: msvc + arch: x86 + cache: true + + - uses: actions/checkout@v4 + + - name: Run CMake + run: cmake -Bbuild -D BOOST_ROOT=C:\runner\boost/boost\ . + + - name: Build CMake + run: cmake --build build diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.gitignore b/lib/libsomeip-c/vsomeip-3.5.1/.gitignore new file mode 100644 index 00000000000..1c6a58ba8bc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.gitignore @@ -0,0 +1,17 @@ +/CMakeFiles +/build*/* +/examples/hello_world/build +/.idea/ +/.vscode/ +/.settings +/.project +/.cproject +/doc +/daemon/CMakeFiles +/examples/CMakeFiles +/implementation/configuration/include/internal.hpp +/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp +/tools/CMakeFiles +/Testing +/logs +!build_qnx/* diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.pre-commit-config.yaml b/lib/libsomeip-c/vsomeip-3.5.1/.pre-commit-config.yaml new file mode 100644 index 00000000000..cf102622c6e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +fail_fast: false +repos: + - repo: https://github.com/pocc/pre-commit-hooks + rev: v1.3.5 + hooks: + - id: clang-format + args: [-i] diff --git a/lib/libsomeip-c/vsomeip-3.5.1/.tests-whitelist b/lib/libsomeip-c/vsomeip-3.5.1/.tests-whitelist new file mode 100644 index 00000000000..29d4805c5ea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/.tests-whitelist @@ -0,0 +1,39 @@ +# This file contains a list of test identifiers that are known to be flaky or non-critical. +# Tests listed here are allowed to fail without causing the overall test job to fail. + +# client_id_tests +client_id_test_utility +client_id_test_utility_masked_511 +client_id_test_utility_masked_4095 +client_id_test_utility_masked_127 +client_id_test_utility_discontinuous_masked_511 + +# initial_event_tests +initial_event_test_diff_client_ids_diff_ports_udp +initial_event_test_diff_client_ids_diff_ports_tcp +initial_event_test_diff_client_ids_diff_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_same_ports_udp +initial_event_test_diff_client_ids_same_ports_tcp +initial_event_test_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_tcp +initial_event_test_multiple_events_diff_client_ids_diff_ports_udp_and_tcp +initial_event_test_multiple_events_diff_client_ids_same_ports_udp +initial_event_test_multiple_events_diff_client_ids_same_ports_tcp +initial_event_test_multiple_events_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_tcp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp_and_tcp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_tcp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_tcp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp_and_tcp +initial_event_test_diff_client_ids_diff_ports_client_subscribes_twice diff --git a/lib/libsomeip-c/vsomeip-3.5.1/AUTHORS b/lib/libsomeip-c/vsomeip-3.5.1/AUTHORS new file mode 100644 index 00000000000..cc7c1265924 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/AUTHORS @@ -0,0 +1 @@ +Bayerische Motoren Werke Aktiengesellschaft (BMW AG) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/Android.bp b/lib/libsomeip-c/vsomeip-3.5.1/Android.bp new file mode 100644 index 00000000000..03fec15209b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/Android.bp @@ -0,0 +1,187 @@ +libvsomeip_srcs = [ + "implementation/endpoints/**/*.cpp", + "implementation/logger/**/*.cpp", + "implementation/tracing/**/*.cpp", + "implementation/message/**/*.cpp", + "implementation/routing/**/*.cpp", + "implementation/runtime/**/*.cpp", + "implementation/utility/**/*.cpp", + "implementation/plugin/**/*.cpp", + "implementation/protocol/**/*.cpp", + "implementation/security/**/*.cpp", +] + +libvsomeip_compat_srcs = [ + "implementation/compat/message/src/*.cpp", + "implementation/compat/runtime/src/*.cpp", +] + +libvsomeip_cfg_srcs = [ + "implementation/configuration/src/*.cpp", +] + +libvsomeip_e2e_srcs = [ + "implementation/e2e_protection/src/*.cpp", +] + +libvsomeip_sd_srcs = [ + "implementation/service_discovery/src/*.cpp", +] + +cc_defaults { + name: "vsomeip_defaults", + cpp_std: "c++17", + + cppflags: [ + "-fexceptions", + "-Wno-non-virtual-dtor", + "-Wno-unused-const-variable", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-lambda-capture", + "-Wno-unused-variable", + "-Wno-unused-local-typedef", + "-Wno-sign-compare", + "-Wno-format", + "-Wno-header-guard", + "-Wno-overloaded-virtual", + "-Wno-implicit-fallthrough", + "-Wno-error", + "-Wno-shorten-64-to-32", + "-D_GTHREAD_USE_MUTEX_INIT_FUNC", + "-D_GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC", + ] +} + +cc_defaults { + name: "vsomeip_lib_defaults", + + cflags: [ + "-DVSOMEIP_BOOST_VERSION=107100", + "-DVSOMEIP_INTERNAL_SUPPRESS_DEPRECATED", + ], + + local_include_dirs: [ + "interface" + ] +} + +cc_library_shared { + name: "libvsomeip3", + vendor: true, + + srcs: libvsomeip_srcs, + + defaults: [ + "vsomeip_defaults", + "vsomeip_lib_defaults" + ], + + cflags: [ + "-DWITHOUT_SYSTEMD", + "-DVSOMEIP_VERSION=\"3.5.1\"", + "-DVSOMEIP_COMPAT_VERSION=\"3.5.1\"", + "-DVSOMEIP_BASE_PATH=\"/vendor/run/someip/\"", + "-DUSE_DLT", + ], + + ldflags: [ + "-Wl,-wrap,socket", + "-Wl,-wrap,accept", + "-Wl,-wrap,open" + ], + + rtti: true, + + export_include_dirs: [ + "interface" + ], + + shared_libs: [ + "libboost_system", + "libboost_thread", + "libboost_filesystem", + "liblog", + "libutils" + ] +} + +cc_library_shared { + name: "libvsomeip_cfg", + vendor: true, + + srcs: libvsomeip_cfg_srcs, + + defaults: [ + "vsomeip_defaults", + "vsomeip_lib_defaults" + ], + + rtti: true, + + shared_libs: [ + "libvsomeip3", + "libboost_system", + "libboost_filesystem" + ] +} + +cc_library_shared { + name: "libvsomeip_e2e", + vendor: true, + + srcs: libvsomeip_e2e_srcs, + + defaults: [ + "vsomeip_defaults", + "vsomeip_lib_defaults" + ], + + rtti: true, + + shared_libs: [ + "libvsomeip3" + ] +} + +cc_library_shared { + name: "libvsomeip_sd", + vendor: true, + + srcs: libvsomeip_sd_srcs, + + defaults: [ + "vsomeip_defaults", + "vsomeip_lib_defaults" + ], + + rtti: true, + + shared_libs: [ + "libvsomeip3", + "libboost_system" + ] +} + +cc_library_shared { + name: "libvsomeip", + vendor: true, + + srcs: libvsomeip_compat_srcs, + + defaults: [ + "vsomeip_defaults", + "vsomeip_lib_defaults" + ], + + rtti: true, + + export_include_dirs: [ + "interface" + ], + + shared_libs: [ + "libvsomeip3", + "libboost_system" + ] +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/Android.mk b/lib/libsomeip-c/vsomeip-3.5.1/Android.mk new file mode 100644 index 00000000000..a7ccbc57784 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/Android.mk @@ -0,0 +1,216 @@ +# Cannot convert to Android.bp as resource copying has not +# yet implemented for soong as of 12/16/2016 + +LOCAL_PATH := $(call my-dir) + +# config/vsomeip.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# config/vsomeip-local.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip-local.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip-local.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# config/vsomeip-tcp-client.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip-tcp-client.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip-tcp-client.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# config/vsomeip-tcp-service.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip-tcp-service.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip-tcp-service.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# config/vsomeip-udp-client.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip-udp-client.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip-udp-client.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# config/vsomeip-udp-service.json config file +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := vsomeip-udp-service.json +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vsomeip +LOCAL_SRC_FILES := config/vsomeip-udp-service.json +LOCAL_PROPRIETARY_MODULE := true +#include $(BUILD_PREBUILT) + +# +# libvsomeip3_dlt +# +include $(CLEAR_VARS) + +LOCAL_MODULE := libvsomeip3_dlt +LOCAL_MODULE_TAGS := optional +LOCAL_CLANG := true +LOCAL_PROPRIETARY_MODULE := true + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/interface \ + +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/endpoints) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/logger) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/tracing) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/message) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/routing) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/runtime) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/utility) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/plugin) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/security) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/interface \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libutils \ + libboost_system \ + libboost_thread \ + libboost_filesystem \ + +LOCAL_CFLAGS := \ + -std=c++17 \ + -frtti \ + -fexceptions \ + -DWITHOUT_SYSTEMD \ + -DVSOMEIP_VERSION=\"3.5.1\" \ + -DVSOMEIP_BASE_PATH=\"/vendor/run/someip/\" \ + -Wno-unused-parameter \ + -Wno-non-virtual-dtor \ + -Wno-unused-const-variable \ + -Wno-unused-parameter \ + -Wno-unused-private-field \ + -Wno-unused-lambda-capture \ + -Wno-unused-variable \ + -Wno-unused-local-typedef \ + -Wno-sign-compare \ + -Wno-format \ + -Wno-header-guard \ + -Wno-overloaded-virtual \ + +include $(BUILD_SHARED_LIBRARY) + +# +# libvsomeip-cfg_dlt +# +include $(CLEAR_VARS) + +LOCAL_MODULE := libvsomeip-cfg_dlt +LOCAL_MODULE_TAGS := optional +LOCAL_CLANG := true +LOCAL_PROPRIETARY_MODULE := true + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/interface \ + +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/configuration) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/interface \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libutils \ + libboost_system \ + libboost_thread \ + libboost_filesystem \ + libvsomeip3_dlt \ + +LOCAL_CFLAGS := \ + -std=c++17 \ + -frtti \ + -fexceptions \ + -DWITHOUT_SYSTEMD \ + -DVSOMEIP_VERSION=\"3.5.1\" \ + -DVSOMEIP_BASE_PATH=\"/vendor/run/someip/\" \ + -Wno-unused-parameter \ + -Wno-non-virtual-dtor \ + -Wno-unused-const-variable \ + -Wno-unused-parameter \ + -Wno-unused-private-field \ + -Wno-unused-lambda-capture \ + -Wno-unused-variable \ + -Wno-unused-local-typedef \ + -Wno-sign-compare \ + -Wno-format \ + -Wno-header-guard \ + -Wno-overloaded-virtual \ + +include $(BUILD_SHARED_LIBRARY) + +# +# libvsomeip_dlt +# +include $(CLEAR_VARS) + +LOCAL_MODULE := libvsomeip_dlt +LOCAL_MODULE_TAGS := optional +LOCAL_CLANG := true +LOCAL_PROPRIETARY_MODULE := true + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/interface \ + +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/compat/message) +LOCAL_SRC_FILES += $(call all-cpp-files-under,implementation/compat/runtime) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/interface \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libutils \ + libboost_system \ + libboost_thread \ + libboost_filesystem \ + libvsomeip3_dlt \ + +LOCAL_CFLAGS := \ + -frtti \ + -fexceptions \ + -DWITHOUT_SYSTEMD \ + -DVSOMEIP_VERSION=\"3.5.1\" \ + -DVSOMEIP_COMPAT_VERSION=\"3.5.1\" \ + -DVSOMEIP_BASE_PATH=\"/vendor/run/someip/\" \ + -Wno-unused-parameter \ + -Wno-non-virtual-dtor \ + -Wno-unused-const-variable \ + -Wno-unused-parameter \ + -Wno-unused-private-field \ + -Wno-unused-lambda-capture \ + -Wno-unused-variable \ + -Wno-unused-local-typedef \ + -Wno-sign-compare \ + -Wno-format \ + -Wno-header-guard \ + -Wno-overloaded-virtual \ + -Wl,-wrap,socket \ + -Wl,-wrap,accept \ + -Wl,-wrap,open \ + +include $(BUILD_SHARED_LIBRARY) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/CHANGES b/lib/libsomeip-c/vsomeip-3.5.1/CHANGES new file mode 100644 index 00000000000..ca972564bc2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/CHANGES @@ -0,0 +1,1392 @@ +Changes +======= + +v3.5.1 +- Restructure Network Tests CMakeLists +- policy.cpp unit test +- Remove deprecated usage of byteorder and use bithelper +- unblock endpoint when closing it +- Find_Debounce_Time made configurable +- Check if configuration_ pointer exists before using +- Initialize routing_state_ +- Solved data race in configuration_impl class +- utility.cpp unit tests +- unit tests payload_impl +- unit tests serializer +- unit tests deserializer +- Unit Tests for policy_manager_impl.cpp +- Unit Test - Routing Manager set_routing_state +- Move documentation to markdown +- clang-format to verify the code vsomeip-lib +- fix deadlock with event and message debounce feature +- disabled some groups of tests +- Try to force connection reset on suspend +- Call availability handler on request service instance +- Handle endpoint queue size underflow +- Add Valgrind massif tool +- Create new train after scheduling to avoid duplicate messages +- Re-Added offer_tests group in all sanitizers tests +- removed extra DLT logs of the policies print +- COVESA-615: vsomeip.lck file not removed upon application termination +- COVESA-527: Locally switch off -Wstringop-overflow +- Create network regression test for specific issue +- Change IndentPPDirectives rule in clang-format +- applied auto in some identified lines by sonarqube +- Add Valgrind memcheck +- Ensure buffer is valid before de-referencing pointer +- Renaming folder test and fixing typos +- Fix minor formatting issues from some commits +- Adds interger overflow check +- Adds application name on cout logs +- Adding helgrind, to test output +- Boost 1.65 cleanup +- network_test - Offer Stop Offer test +- Support host name (env) for internal TCP communication +- Remove cached configuration after app stops +- Optimize tests/network-tests/CMakeLists.txt +- Check if pointer exists before dereferencing it +- avoid requiring valgrind locally +- Fix Lock-Order-Inversion in policy_manager_impl +- Revert "Fix to not ignore stop offers when sd acceptance is not required" +- Fix timeout on offer_stop_offer test +- Restore config_plugin_impl mutex +- Rework [STOP_]OFFER command handling +- some-tp memory consumption increasing fast +- Remove dlt traces from memory_test +- restart_routing_test enabled +- Fix cyclic events +- Tracing LOI +- improve connection log on error path +- added subscribe_notify groups to non-leak verification +- Relocate hostname config command +- allow subscribeACK if at least one offer was sent by SD +- Improve "end of file" error handling +- Update Clang-Format to Version 18 +- Debounce tests fix +- Wireshark dissector for vsomeip protocol +- Remove logging on operation cancel in connect_cbk +- Add additional info on failure to open TCP port +- Implementation of SOMEIPSD_00577 +- Refactor how niceness values are applied to threads +- prevent race between event expiration/forwarding +- Fix subscribe_notify_one tests +- Fix missing/blocked subscription requests +- change references to C++14 into C++17 +- Explicitly check whether an endpoint is in use +- Enabled all network tests with whitelist +- Fix target client id in local_send +- remove redundants package import definitions +- run unit tests on windows +- Fix debounce network tests +- type upgrade and temporary disable of test for QNX build +- Force abort hanging detached threads +- Application tests fix +- Remove behavior from catch block in ~message +- Stop/Start (network) endpoints on suspend/resume +- Reduce the number of copy operations on event payloads +- Sets linger to 0 in local tcp clients +- Prevent exception re-throw in ~message +- remove linger on local_tcp +- Fix android traces build +- Introduce stateful availability handler +- Update the availability state +- Reintroduces the TIME_WAIT for ltcei +- Faster handlers lookup +- Increase app registration timeout +- Force endpoint restart if re registering +- fix semaphore logs +- fix compile issue with pthreads in android +- Disabling set routing state unit test +- Fixing get_policy_manager error with security disabled + +v3.5.0 +- Load Policies Lazy Load +- Test - Processing SD messages with unknown type option +- ensure endpoints before deletion +- Improve "end of file" error handling +- Enable debouncing of events & selective events +- Revert "Test - Processing SD messages with unknown type" +- Logs added to points of failure on registration process +- One *.json to ignorem all +- Someip-tp remote address rework +- Fix crash in multicast_receive receive_cb +- Generate network_test configs directly to build +- Fix deadlock if binding of TCP client endpoint fails +- Added missing includes of iomanip to support compilation on Mint +- Cache not yet registered events +- Return true to make sure endpoints are deleted +- Byteorder implementation +- Reorder of prepare_stop method +- Allows applications in the same process using different security configurations +- Fix to not ignore stop offers when sd acceptance is not required + +v3.4.10 +- Fix QNX build +- Fix missing Stop Offer +- Apply extra fixes to QNX environment +- Remove key <service, instance> from the offer_commands_ +- COVESA#478: deleted unused param _use_exclusive_proxy +- Fix code smell related to condition variable +- COVESA#462: Fix IPv6 Service Discovery +- Added multicast_mutex to async function that makes use of multicast socket +- COVESA#479: Allow service_discovery to continue without random_device +- Fix availability handler sending false on offer +- Set host/port in vsomeip_sec_client_t whenever possible +- Use executor_work_guard instead of io_context::work for boost v1.66 and higher +- Update Windows build +- Added profile 07 as an option for E2E protection +- ASIO: use heap-allocation to avoid using garbage data +- Fix integer underflow in server_endpoint_impl.cpp +- Cleanup prepare_stop_handlers_ +- Automatic unsubscribe +- Debounce now works without routingmanagerd running +- Debouncing: Send last received value after debounce time + X +- Fix resource deadlock avoided crash +- Use closure instead of callable struct + +v3.4.9 +- Merge COVESA PR447 with support for QNX 7.1 +- Merge COVESA PR470 with changes to not instantiate +a non existent type for boost < 1.66.0 +- Merge COVESA PR515 with changes that remove not used lines + +v3.4.8 +- Adds debounce_filter_tests json files to gitignore +- Adds check for null serviceinfo +- Implementation of debounce frequency test +- Accept malformed StopSubscribe/Subscribe messages +- security: Fix security library name +- Also remove service instance from map of pending offers +- enforce lock acquisition order to avoid LOI +- Improved logs + +v3.4.7 +- Do _NOT_ try to serialize empty names +- Avoid crash on access to invalid position from tcp_endpoint buffer +- Fix security library name +- revert std::move usage in train buffer's +- Fix deadlock in mutex_ + +v3.4.6 +- check if a policy exist in the vector of policies +- Crash in process vsomeipd crash id: D8DF38B19EEBC79D +- Enable guest port configuration per uid/gid + +v3.4.5 +- Implementation of new debounce filter test +- test availability when double offering service +- network test fixes +- Try to synchronize subscribe/unsubscribe/resubscribe +- Add vsomeip_portcfg.json to the list of mandatory configuration files +- Check buffer before accessing it +- Rework condition for starting the send operation for client endpoint +- Avoid spamming the log +- Extend security interface to enable syncing security clients +- Revert get_local_port() behaviour + +v3.4.4.1 +- manually reset tables for unavailable services on suspend state + +v3.4.4 +- Fix deadlock if binding of UDP client endpoint fails +- Changed local_tcp_client endpoint connect to async connect. +- Change shutdown sequence +- vSomeIP Security: Update vsomeip_sec + +v3.4.3 +- Fixed race between incoming subscription and StopOffer/Offer + +v3.4.2 +- Removed local_port_ attribute + +v3.4.1 +- Rename the new "register_message_handler" overload function +- Set the Client identifier when sending pong command + +v3.4.0 +- Allow to register multiple message handlers for the same message +- load_security_policy_extensions Unit and Benchmark Tests +- Fix is_local flag for acl acceptance msg +- Fix registration issues regarding connecting timeout + +v3.3.8 +- Check buffer size when serializing/deserializing event registrations +- Remove leftovers from shm usage +- Avoid using uninitialized variable +- Displays lib version when starting any app + +v3.3.7 +- Fix handling of endpoint options +- Fix build on Windows +- Fix client-side logging filters +- Rework in event::set_payload +- Release no longer in use client endpoints +- Rework condition for starting the send operation +- Verify if the event is shadow + +v3.3.6 +- The "last forwarded" timestamp must be handled per event +- Fix deadlock +- Restart the connection on broken unix sockets +- Fix routing root not binding to local tcp if +- Rework connecting timeout + +v3.3.5.1 +- Fix typo in application_impl.cpp +- Update load_balancing_option_impl.cpp +- Fix format specifier in memory_log_timer_cbk +- Prevent boost symbols from leaking into global namespace +- Remove redundant ostream manipulators +- Fix for configuration option deserialize bug +- Accept return codes within range 0x20 - 0x5E as valid + +v3.3.5 +- Do NOT use iterators in asynchronous operations. +- Add event identifier to "REGISTER EVENT" log message at routing manager stub. +- Fix for crash in flush function, server_endpoint_impl class +- added FD_CLOEXEC flag in all open operations +- Use "make_unique" and "make_shared" to construct "unique_ptr" and "shared_ptr" +- Removed redundant pairs of parentheses +- Do not erase while iterating. +- Changed invalid call of deserialize to serialize +- Fixed the the problem in policy::deserialize counts down the given policy size, +and after deserializing the policy it is 0. +- Monitor session IDs in SD messages and log missing IDs +- Fix timestamp format of log message +- Prevent crash when logging with DLT +- load_security_update_whitelist Unit and Benchmark Tests +- Added protection when a message is destroyed +- Pu/connect timeout refactor +- Rework the addition of services when in suspended mode +- Remove const qualifier from function return types +- Adapt to boost 1.81.0 + +v3.3.4 +- Removed VSOMEIP_DEPRECATED_UID_GID from some elements. +- Add nullptr guards to receive_cbk. +- Add nullptr check to receive_cbk. +- Fix network test build for g++11.3. +- Remove mutexes from logger_impl and security_impl. +- Fix VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE buffer. +- Fix range-loop-construct warning for g++11.3. +- Implementation of support for header-only tracing. +- Fix applied regarding the timeout in endpoints connections. +- Use standard reliability_type_e on service_discovery_impl. +- Added receive operation for UDP server endpoints. +- Reduce log level of some vsomeip messages. +- Change dependency on LINK UP. +- Change rejoining mechanism in UDP server endpoint. + +v3.3.3 +- Fixed android build issues +- Added more DLT log info on credentials error +- Fixed ICON register issues. +- Added an unlocked method to get the policy extension path + +v3.3.2 +- Manage E2E Profile04 counters per instance +- Fix handling of subscription objects during unsubscribe. +- Remove subscription on connection resets. +- Reuse local client ports. +- Add try block in message deserialization. +- Remove unneeded / unused structure servicegroup. +- Optimize event/field registration. +- Add dependency from network tests to e2e library (plugin). +- re-introduce the definition of socket timeout. +- pu/event-tests: Avoid deadlock. +- Linux: avoid static initialization of std::mutex. +- Improve robustness when stopping initial-event tests. +- Fixed various unused-variable warnings. +- Handling with some udp errors in send_cbk process. +- Avoid services becoming available when the daemon is suspended. +- refactor: remove `set_bound_sec_client()` from `local_tcp_server_endpoint_impl`. + +v3.3.1 +- Refactor `plugin_manager_impl::load_symbol()` +- Use consistent naming for `security::is_client_allowed_to_access()` +- Raise C++ standard used to C++17 on non-Windows platforms +- Prefer using reinterpret_cast instead of C-style casts +- DRYer approach to loading `libvsomeip_sec` hook functions +- Indent with 4-spaces +- Hide `symbol_table` inside `security::load()` +- `policy_manager::get()` should call `policy_manager_impl::get()` +- Fix integer conversion warning +- Refine silencing MSVC warning C4101 +- Add `VSOMEIP_DISABLE_SECURITY` in a few remaining spots +- Add support for `vsomeip_sec_client_t` to subscription handlers +- Disable security unit/benchmark tests when `DISABLE_SECURITY` +- Disable security network tests when `DISABLE_SECURITY` +- Make the sec client a member of the connection +- Add support for TCP clients in the default security hooks +- Fix security checks when using internal TCP sockets + +v3.3.0 +- Introduced protocol classes +- Extended interface to allow application specific configurations +- Allow to switch off internal routing +- Added ACL plugin +- Respect subscription status handler for ANY_EVENT +- Corrected handling of ANY_[SERVICE|INSTANCE|EVENTGROUP|EVENT] when handling subscription status +- Fix handling of lock files +- Add subnet support for IPv6 networks (boost 1.66+ only for now) +- Fix client specific debouncing +- Set SO_REUSEADDR before binding socket +- Specify local IP/interface when joining multicast group +- Avoid false positives when warning about not having loaded acceptance data +- Extended buffer size adaptation for UDP sockets +- Removed leftover from attempt to fix setsockopt blocking +- Implemented a cache for is_client_allowed +- Adapted version in OSS information +- Log errors (connection reset, end of file, bad descriptor) as such +- Rename extended "subscribe" method to "subscribe_with_debounce" + +v3.2.15 +- Unit/Benchmark tests for Security::Check Credentials +- Client dependent usage of session handling +- Fix Windows build +- Fix for multicast_socket bug +- Fixed spam messages of security policy extensions +- Added OSS information for RSE + +v3.2.14 +- Implementation of support for header-only tracing +- Replaced exceptions with error messages +- Asynchronously set join/leave options +- React on failed option setting +- Prevented StopSubscribe/Subscribe on first offer reception +- Implemented a cache for is_client_allowed operations + +v3.2.13 +- Fixed lock_guard and mutexes on lazy load policies + +v3.2.12 +- Fixed race condition on startup of suspend_resume_test +- Added a default initialize in tcp_client_endpoint_impl::is_sending +- Updated the log "Maximum number of dispatchers exceeded" +- Refactored the policy extensions map +- Added protection for Received buffer size and buffer capacity +- Added nullptr checks to some pointers in the eventgroupinfo +- Fixed Windows build +- Removed print error messages for unneeded endpoints +- Wrapped accept method to use accept4 +- Improved reliability of multicast leave group + +v3.2.11 +- Fix incorrect load of policies +- Fix unlocked access to multicast_info +- Rework the join mechanism. +- Fix receiving of routing info messages in TCP mode. +- Make routing client port range configurable ("routing-client-ports"). +- Allow to configure event update properties. + +v3.2.10.1 +- Fix false positive security warning + +v3.2.10 +- Fix race condition which could lead to not establishing a TCP + connection to a remote service + +v3.2.9 +- Send StopSubscribe and clear subscribed_ map on STR +- Added suspend/resume test +- Erase subscribed_ map on received StopOffer +- Select new local port on bind error for uce + +v3.2.8 +- Fixed credentials::receive_credentials() error handling +- Ensured to call prepare_stop handler for TCP server endpoints + +v3.2.7 +- Fixed lock order inversion + +v3.2.6 +- Adapted helloworld references within user guide +- Added nullptr check for remote subscription pointers + +v3.2.5 +- Fixed race condition in client endpoint send queue +- Improved robustness when receiving malformed remote subscriptions +- Cleanup remote subscribers on suspend +- Make sure that the connection (and thus the policy loading) + has taken place before checking something against the policies + +v3.2.4 +- Removed load of the vsomeip_ext policies from the start +- Allow to partition service instances. Each partition uses a separate client + port, even if service instances from different partitions are offered on the + same server port of a remote device. +- Fixed timer restart (detection of last received SD message) +- Optimized distribution of credentials- Improve handling of expired subscriptions +- Fix event payload caching at proxy +- Select a free client port that was not used recently +- Fixed invalid insertion in known_clients_ map +- Fixed clearing of client endpoints +- Rework for expire_subscriptions() +- Rework map insertions +- Avoid deadlocks during expiration of subscriptions + +v3.2.3 +- Optimized updating the sent counter for FindService messages in requested_ map +- Improved log messages +- Enabled tracing for initial values of shadow events for subsequent subscribers. +- Reduced the vsomeip security logging +- Fixed race condition in the logger +- Fix for initial events +- Fixed crash in TCP client endpoint +- Fixed TCP socket bind error handling +- Selected new local port on bind error for tce. +- Ignored subscribes when suspended +- Added subscriber count to log / extended config switches +- Limited subscriptions to same service, instance, eventgroup depending on remote IP +- Synchronized update_remote_subscription / send_(un)subscription() +- Fixed lazy loading on daemon + +v3.2.2 +- Fixed the loading of the security policies at the start +- Fixed the tags in the android logging +- Added the additional client ports in the ipsec-plugin default configuration +- Removed the unneeded socket option IPPROTO_IP/IPPKTINFO. +- Removed the libdlt dependency from android +- Improved the documentation of debouncer configuration. +- Check the port to send notifications +- Fixed the nullptr on multicast_socket +- Improved the sending of STOP_OFFER messages + +v3.2.1 +- Updated cmake minimum required version +- Fixed expire_subscriptions(address) +- Updated examples +- Ensured to clear previous error before calling dlsym (plugin_manager) +- Always send values after subscription acknowledgment- +- Added support to logs in Android +- Updated android build files +- Ensured to forward logs to DLT independently of FILE / CONSOLE log configuration +- Avoided heap-buffer-overflow in look_ahead() when deserializing SD entry +- Adapted the reader of the config to put always logging in Android +- Used error code when starting main phase timer +- Added some SomeIP/TP optimization +- Changed the loglevel for blocked incoming notifications +- Restarted UDP client endpoint on connection refused error +- Acquired mutex before change sd_acceptance_rules_active_ +- Fixed getEnv returning empty value + +v3.2.0 +- Dropped support for boost 1.65 and below +- Do not lock the multicast mutex twice +- Disable warnings for boost and DLT headers +- Fix security credentials update in rm::proxy +- Prevent deletion of server endpoint +- Fix instance removal in local_services_history_ map +- Lazy load security policies +- Use a configuration variable for the SOME/IP-TP maximum segment length +- Use instance based SOME/IP-TP configuration +- Use service configuration within server endpoint +- Ensure maximum segment length is a multiple of 16 (SIP_RPC_772) +- Use configured separation times +- Added debounce test and refined debouncing +- Fix hostname transmission +- Do _NOT_ remove subscription on a received StopOffer +- serviceinfo: Removed unused & undefined member group_ +- Implemented socket wrapper using ld(1)'s "--wrap" +- Set the android LOG_TAG to VSIP +- Added message statistics +- Reworked android logging + +v3.1.18 +- Support boost 1.74 +- Ignore remote offers without referenced endpoint options +- Fixed race condition when removing security policies +- Ensure composite send operations have finished before resetting TCP server endpoint + +v3.1.17 +- Support AutoSAR E2E Profile 4 +- Support dynamic policies for offered services +- Fixed race condition between service shutdown and subscription +- Fixed race condition between service instances offered on the + same endpoint(s). + +v3.1.16 +- Fixed race condition when leaving multicast group +- Do not busy loop when receiving garbage data on local endpoint + +v3.1.15 +- Ensure to remove the correct subscription object on unsubscribe +- Implemented support to define "secure services" +- Speedup security policy handling +- Enable building with boost v1.73.0 + +v3.1.14 +- Fixed race conditions (application registration, subscription) + +v3.1.13 +- Abort operation when doing a full rejoin +- Protect access when consuming a policy +- Decrease wait time for composite send operations +- Reimplemented logger without using boost::log + +v3.1.12 +- Ensure composite send operations have finished before resetting an endpoint. + Otherwise this may cause a crash within boost.asio. +- Always use the assigned client identifier when sending messages from a proxy. +- Add TTL to initial timestamp to avoid immediate expiration. + +v3.1.11 +- Preparation for new IPsec plugin (3.1.1) + +v3.1.10 +- Reset subscriptions on stop offer service +- Protect access to security policy contents +- Tolerate wrong/incomplete event registrations in compatibility mode +- Avoid buffering of pending subscriptions + +v3.1.9 +- Fix race condition when processing multicast messages + +v3.1.8 +- Fix deadlock when sending messages +- Fix race condition when processing SD messages + +v3.1.7 +- Fix stop subscribes when a service is released +- Improve handling of time stamps when processing subscriptions +- Log queued data instead of socket fill levels +- Ensure all shutdown steps are executed (even in case of exceptions) + +v3.1.6 +- Fix possible busy loop when expiring subscriptions +- Use set of serializers to avoid deadlock situation +- Improve client identifier handling + - Check whether corresponding socket is available + - Implement retry if a client identifier cannot be used +- Log buffer fill levels if they exceed a configurable threshold (default=67%). + +v3.1.5 +- Ensure subscriptions to remote services are correctly reset when + services are no longer available. +- Fix race condition when inserting new subscriptions. +- Fix accessing of security module during library shutdown. + +v3.1.4 +- Ensure to only mark remote services offered via UDP and TCP as + available when both endpoints are marked as connected to prevent TCP + connection restarting by the service discovery. +- Fix possible deadlock when expiring a remote subscription and + sending the corresponding event at the same time. +- Fix nullptr access in service discovery when receiving a + subscription for an unknown eventgroup. +- Add new cmake variables DEFAULT_CONFIGURATION_FOLDER and + DEFAULT_CONFIGURATION_FILE which can be used to change the default + configuration folder and file at compile time (see vsomeipUserGuide + for more information) +- Fix race condition leading to not accepting service offers from + a local client when the same service was offered and stop offered in + a high frequency + +v3.1.3 +- Set client ID to 0x0 for SOME/IP SD messages + +v3.1.2 +- Fix bug in vSomeIP 2 compatibility layer which lead to offering + selective events as normal events in conjunction with + CommonAPI-SomeIP mainloop integration when a proxy was build to a + stub through the same CommonAPI connection ID in the same binary. + +v3.1.1 +- Ensure sending StopOffers for services specified with a different + protocol than someip in the configuration. +- Add support for boost v1.70 and v1.71. + +v3.1.0 +- Integrate changes of 2.14.12 - 2.14.18 +- Add get_uid and get_gid methods to message class +- Add reliability parameter to application::offer_event and + application::request_event methods +- Add vSomeIP 2 compatibility layer. +- Fix crash when expiring a reliable-only subscription +- Fix Android compile errors +- Fix bug in service discovery offer acceptance handling which led to + only checking the first service entry of an incoming SD message via + the registered handler. +- Deactivate adherence to NPDU debounce time between SOME/IP-TP + segments of the same message. +- Fix less than operator of remote_info_t which lead to + application::get_sd_acceptance_required() always returning a map + with only one erroneous element +- Fix SD startup on Windows +- Fix heap-use-after-free in server endpoints + +v3.0.0 +- Cleanup of application interface + - Removed (un)register_subscription_error_handler methods. The + functionality is now offered through the + (un)register_subscription_status_handler methods. + - All methods concerning events/fields now use a new event_type_e + enum to specify the event type. + - The subscription_type_e parameter was removed from the subscribe + method. The way the remote service is offered now determines the + subscription type. + - The offer_acceptance* methods were renamed to sd_acceptance*. + - The flush parameter was removed from the send method + - Removed notify and notify_one methods which used the flush + parameter. +- Added SOME/IP-TP functionality. Please see the vsomeipUserGuide for + more information. +- Added nPDU functionality. Please see the vsomeipUserGuide for more + information +- E2E protection is now implemented as plugin +- Added Android support +- Internal improvements and bugfixes + +v2.14.18 +- Fix bug leading to not sending out FindService entries after a + resume from Suspend-to-RAM, if the service was already known at the + time of the request. + +v2.14.17 +- Performance improvements for request-service message handling + +v2.14.16 +- Ensure restarting of TCP connection if TCP reset is received + before 3 way handshake is finished + +v2.14.15 +- Ensure that all clients receive the security policy update + +v2.14.14 +- Improved handling for EMFILE error (per-process limit of open + filedescriptors reached) +- Fixed client ID assignment + +v2.14.13 +- Fixed race condition leading to unintended sending + of selective broadcasts. + +v2.14.12 +- Make timeout during application shutdown configurable via + "shutdown_timeout" json configuration file parameter +- Fix bug leading to too fast reassignment of client IDs acquired via + auto-configuration in conjunction with usage of a non-continuous + diagnosis mask + +v2.14.11 +- Fixed race condition when opening shared memory +- Fixed race condition when inserting SubscribeEventGroupACK + entries +- Added prefix for security related log messages + +v2.14.10 +- Fixed race condition in client ID to UID mapping. + +v2.14.9 +- Fixed race condition in event / response validation + and client ID to UID mapping removal +- Limit reconnect attempts of local client endpoints +- Increase robustness of local server endpoint + in case of corrupted data stream + +v2.14.8 +- Handle ANY_METHOD for security policy updates + +v2.14.7 +- Reverted security related feature if same client connects + again with different credentials. + +v2.14.6 +- Fixed issue related to client ID reuse if security is activated +- Use chmod instead of umask to ensure correct permissions of unix + domain sockets + +v2.14.5 +- Fixed race condition when handling security policy updates + +v2.14.4 +- Added whitelist feature for security policy update / removal +- Added / improved security related checks + +v2.14.3 +- Prevent concurrent access to any client policies +- Updated ACL plugin interface + +v2.14.2 +- Fix possible deadlock when receiving invalid responses from remote + TCP services +- Enabled loading of UID GID specific security configuration during + application startup + +v2.14.1 +- Check header fields in udp endpoints for correct values +- Fixed race condition in event::notify methods +- Ensure to always resume sending if endpoints were restarted +- Prevent possible concurrent access to receive buffer in endpoints +- Allow or deny all remote clients via security config parameter +- Adapt security config plugin to updated ACL interface +- Make receive buffer size configurable for UDP client and + server endpoints via "udp-receive-buffer-size" parameter + in json configuration file +- Fix race condition which could lead to premature resubscription if a + remote service was stop offered and offered again + +v2.14.0 +- Introduce security policy updates during runtime and extend + security configuration to filter on instance ID and method ID level + For more information see the vsomeipUserGuide. +- Make IPsec plugin more robust against libdavici communication loss + +v2.13.2 +- Make I/O thread nice level configurable + +v2.13.1 +- Improve check of subnet mask for remote subscribers +- Restart TCP connections if too big messages are received +- Don't process subscriptions if IPsec connection isn't established +- Additionally check protocol header fields in tcp endpoints as well +- Fix race when expiring remote services + +v2.13.0 +- Update debug_diagnosis_plugin and add update_service_configuration + method to public application interface. This enables offering of + service instances on the network which are only offered locally by + default. The changes done through the new method are not persistent + over reboots. +- Fix handling of requests send to the service discovery port +- Log time since routing state was set to RS_RESUMED in cyclic version + logger +- Blame externally offered services if routing state is set to + RS_SUSPENDED +- Prevent possible exception during application shutdown + +v2.12.4 +- Improve handling of reboot detection in IPsec plugin if the + same ipsec connection is still used after reboot. + +v2.12.3 +- Improve handling of broken TCP streams + +v2.12.2 +- Expire remote subscriptions to local services when routing state is set to + suspending + +v2.12.1 +- Fixed race condition in event registration + +v2.12.0 +- Improve error handling and STR behaviour of IPsec plugin. +- Improve magic cookie handling. +- Fix possible deadlock on application shutdown +- Fix handling of local StopOffers when duplicate service instances + are present in the network. +- Make trace connector json configuration more flexible +- Fix bug in security configuration when black listing single + UIDs/GIDs + +v2.11.2 +- Ensure service availability if IPSec plugin is activated but IPsec + not configured correctly. + +v2.11.1 +- Improve handling of slow remote ECUs in IPsec plugin +- Fix possible deadlock on application shutdown + +v2.11.0 +- Added IPsec plugin. + The compilation of the plugin has to be explicitly enabled when calling cmake. + Example: cmake -DPLUGIN_IPSEC_BUILD=1 .. + +v2.10.22 +- Handle EPERM error (Operation not permitted) in cei::send_cbk +- Restart TCP endpoint if a maximum number of aborted restarts + (due to state == CONNECTING) is reached or if a maximum allowed time since + the connection attempt was started has elapsed +- Fixed missing call of subscription status handlers + for external fields if a following subscription + was done triggered by a service being stopped/expired +- Fixed crash in vsomeip security credential check +- Added Debian hardening compiler flags (requires GCC >= 5.2) +- Fixed compilation with GCC 8 + +v2.10.21 +- Improve memory usage of routing manager. +- Improve handling of incoming SD messages with uncommon entry + combinations. +- Name all threads under Linux and log thread IDs during startup. +- Optimize memory allocation for internal message handling. +- Ensure an (extra) dispatch thread is running in case the main + dispatch thread is (still) blocked. +- Fix race condition which could lead to missing initial events for + local subscriptions if the application hosting the service called + application::offer_event and additionally application::request_event + for the same event. +- Fixed crash + +v2.10.20 +- Add security config (i.e. vsomeip_security.json) to mandatory config files +- Enable local_routing_test_starter.sh to use externally defined configuration + files +- Reject malformed subscriptions with SubscribeEventgroupNACK if multiple + endpoint options are referenced +- Use CMake define or environment variable to find gtest +- Quit vsomeipd when Service Discovery is configured but module cannot be loaded +- Added error message when Configuration module cannot be loaded +- Export payload_impl to enable compilation with newer GCC versions +- Avoid printing the same warning twice. Ensure all error paths are identifiable +- Fixed security checks for policies without configured client ID +- Fixed crash on auto config load in case of EOWNERDEAD caused by previous crashed/exited application + +v2.10.19 +- Catch exceptions on shutdown (especially from boost::log) +- Fixed handling of malformed packets in TCP client endpoint in conjunction + with magic cookies + +v2.10.18 +- Fix restarting of TCP connection on connection reset by the server + and mark services reachable through it as unavailable until + connection is established again. +- Fix bug which prevented restarting of TCP connections if the peer + instantly send a RST after the connection had been established. +- Fix bug which could cause missing initial events in conjunction with + service discovery messages containing new subscriptions and + resubscriptions. + +v2.10.17 +- Speedup initial subscriptions to unreliable remote services +- Fix deadlock in conjunction with configured client ports +- Fix bug leading to usage of client port outside of configured range + +v2.10.16 +- Added changes for diagnosis mode plugin (as in v2.10.14) +- Only map shared memory for client IDs once per process + +v2.10.15 +- Reverted diagnosis mode plugin (as in v2.10.11) +- Fix remote event caching + +v2.10.14 +- Added changes for diagnosis mode plugin. +- Bugfix for pending subscriptions when same port is used + for TCP and UDP endpoint option. + +v2.10.13 +- Reverted diagnosis mode plugin + +v2.10.12 +- Fix exception handling for boost logger +- Update diagnosis mode plugin + +v2.10.11 +- Fix client ID handling for remote selective subscriptions +- Add handling for EDESTADDRREQ in endpoints + +v2.10.10 +- Fix concurrency issue leading to a crash + +v2.10.9 +- Improve handling of service discovery messages with entries + referencing too many options. +- Prevent sending of duplicate remote subscriptions to local clients + if the local client processes incoming subscriptions too slow. +- Remote (un)subscriptions to the same eventgroup are now queued in + the routing manager until the local client has processed the + previous (un)subscription for this eventgroup. +- Introduce new json configuration parameter 'diagnosis_mask' to + control the number of bits in the client ID used for the diagnosis + address. This can be used to enable more than 254 concurrent clients + on a node. For more information see the vsomeipUserGuide. +- If the service discovery is enabled it is is only started if a + matching multicast route for the configured service discovery + multicast group is present in the system. This applies only to + Linux. +- Rework security configuration: + - Allow policy specifications without client specification. + - Allow policies to be specified for ranges of uids/gids. + For more information see the vsomeipUserGuide. + +v2.10.8 +- Change dispatching of availability states in case an availability + handler of a service instance is blocked in user code: Availability + states of a service instance are now never dispatched parallel. The + next availability state for a service instance is only dispatched + after the blocked availability handler returned from user code. If + the availability of the service instance changes in the meantime, + subsequent incoming messages of the service instance are queued + until the availability change was reported to the user code. +- Subscriptions to remotely offered services are now always done based + on the protocol(s) the remote service is offered with. The + subscription_type parameter of the application::subscribe method is + ignored. +- Added wildcard support ("any") for the uid and gid json parameters + in the security configuration. +- Fix possible deadlock on application shutdown + +v2.10.7 +- Fix potential deadlock when expiring remote subscriptions +- Rework restarting of tcp client endpoints to prevent heap corruption + under high load situations + +v2.10.6 +- Fix concurrency issue leading to a crash when asynchronous + subscription handlers were used. +- Improved packing of subscriptions sent out as answer to incoming + offer service messages. + +v2.10.5 +- Fix possible deadlock on application shutdown +- Try to reestablish TCP connection on resubscription if the remote + closed the connection +- Introduce new configuration file parameters to control + interpretation of TTL field of incoming remote offers and + subscriptions: + - service-discovery > ttl_factor_offers (optional array of + service/instance/TTL factor tuples) + - service-discovery > ttl_factor_subscriptions (optional array of + service/instance/TTL factor tuples) +- Added possibility to debounce external events/fields + based on time or change of data in the payload (maskable) via new + configuration file parameter: + - debounce (optional array) + For more information see the vsomeipUserGuide. +- Added possibility to limit amount of memory used to cache outgoing + messages on IP port basis or globally via configuration file + parameter: + - endpoint-queue-limits (array): to limit on IP:Port (endpoint) + level + - endpoint-queue-limit-external: to generally limit all external + endpoints. + - endpoint-queue-limit-local: to limit queue sizes for local + communication + For more information see the vsomeipUserGuide. + + +v2.10.4 +- Extended diagnosis plugin to handle requests for + "disableRxAndEnableTx" and "disableRxAndTx". +- Catch unhandled user code exceptions thrown from called handlers. +- Don't send SubscribeEventGroupNACK for pending subscriptions on next + offer to reduce the amount of StopSubscribe/Subscribe messages. +- Added possibility to apply filter for client side logging + using VSOMEIP_CLIENTSIDELOGGING environment variable. + +v2.10.3 +- Interpret all incoming TTLs five times longer in service discovery + to prevent inadvertent expiration of remote offers during high load + situations. + +v2.10.2 +- Fix deadlock in routing manager when processing subscription + acknowledgment from a local client if the corresponding service + instance was stopped in the meanwhile. +- Introduce status_log_interval and memory_log_interval json file + parameters which can be used to cyclically log memory consumption + and/or internal status of the routing manager in a given interval +- Add Debug Diagnosis Job plug-in +- Support definition of multiple client port ranges in configuration + +v2.10.1 +- Fix possible memory corruption in routing manager on TCP connection + reset + +v2.10.0 +- Add register_async_subscription_handler to application interface +- Ensure faster stopping of UDP and TCP endpoints +- StopSubscribe eventgroup entries of StopSubscribe/Subscribe + eventgroup entry sequences in incoming SD messages are now + completely handled in the service discovery module + +v2.9.5 +- Change magic cookie behaviour to only send a magic cookie every 10 + seconds instead of in front of every SOME/IP message +- Fixed bug which prevented resubscription after resuming from + suspended state + +v2.9.4 +- Fixed deadlock on suspend to RAM / resume, triggered + by signal handler. + +v2.9.3 +- Fixed race condition on application shutdown +- Fixed bug that application object was not destroyed +- Enabled client side logging of received messages + to DLT if environment variable VSOMEIP_CLIENTSIDELOGGING + is set to empty string or another arbitrary value. +- Ensure that the correct source port is used for sending events + +v2.9.2 +- fix handling of received response messages for unknown + clients. +- Ensure that all external services are marked as offline when + routing_state is set to RS_SUSPENDED +- Ensure to start sending out FindService messages for requested + services after resuming. +- Ensure that the service info is also deleted if no unreliable + communication happened before the service TTL has expired. + +v2.9.1 +- Don't ignore service requests for UDP-only remote services done + before corresponding OfferService message was received. +- Ensure that main dispatcher thread waits until newly started + dispatcher threads are finished with their call into the user code + before starting to dispatch again after a blocking call occurred. + +v2.9.0 +- Added get_offered_services_async method to application interface to + read the currently offered services +- Added set_watchdog_handler method to application interface which can + be used to register a handler invoked in a given interval. +- Optimize processing time of incoming service discovery messages +- Events are now sent based on their configuration in the json file +- If a remote service is offered reliable and unreliable subscriptions + are now done always with both endpoint options. +- Incoming subscriptions are now not acknowledged if not all events of + the eventgroup can be served with the given endpoint options. + +v2.8.1 +- Support negative filter in trace connector + +v2.8.0 +- Change behaviour of register_subscription_status_handler method of + the application interface: Registered handlers will only be called + if the subscription was accepted by the remote side. +- Add 2nd register_subscription_status_handler method to application + interface with additional flag to enable calling of the registered + handler if the subscription is rejected by the remote side. + +v.2.7.3 +- Fix deadlock when stopping client endpoints to remote services +- Fix deadlock during construction of Subscribe Eventgroup entries + +v.2.7.2 +- Avoid deadlock when printing error message about too large messages + +v2.7.1 +- Prevent processing of too short messages received via UDP +- Avoid catching SIGABRT in vsomeipd +- Prevent duplicate logging of remote messages +- Log message cleanup/enhancement + +v2.7.0 +- Add possibility to register a subscription status handler via + application interface. The handler will be called if a subscription + is acknowledged / not acknowledged by the application hosting the + target service instance of the subscription +- The default subscription type of application::subscribe method was + changed from RELIABLE_AND_UNRELIABLE to PREFER_RELIABLE to harmonize + initial event behaviour +- Add generic plug-in concept +- Fix bug which caused sending out subscription messages containing + endpoint options with port set to zero +- Make magic cookie detection TCP connection based +- Avoid sending unneeded SIGKILLs to current routing manager +- Forward service's instance IDs to DLT +- Fixed performance loss on "client ID" lookup needed for ingoing + remote subscriptions +- Add signal handling for starting stopping the service discovery to + vsomeipd +- The message object can now be asked for CRC check state: + is_valid_crc() +- Incoming remote responses where the CRC check fails will trigger: + set_is_valid_crc(false) + +v2.6.4 +- Fix bug in reboot detection of other nodes +- Improve restarting of TCP connections + +v2.6.3 +- Improve reboot detection of other nodes +- Introduce 'max-payload-size-reliable' json file parameter which can be used to + globally limit the maximum allowed payload size for TCP communication +- Added CRC checksum calculation for bit optimized messages + +v2.6.2 +- Service-Disovery performance improvements +- Made Routing Manager restartable +- Fixed file handle leak caused by remote ECU reboot +- Activate TCP-Keep-Alive for TCP endpoints +- Debouncing of request-service messages (routing info performance) +- Fixed false session-id handling of identification request + +v2.6.1 +- Fixed clearing of subscribers on stop offer service + +v2.6.0 +- Fixed races and crashes +- Fixed repetition phase timings for find service messages +- Reworked internal event/field distribution to reduce CPU load +- Reworked internal routing info distribution leading to fewer and smaller + messages and lower CPU load +- Extend public application interface with second unsubscribe method with + additional event parameter + +v2.5.3 +- Fixed races and crashes +- The minor version of a service instance is considered again when reporting the + service instance's availability (this was removed with v2.4.2). If the minor + version should not be considered use ANY_MINOR or DEFAULT_MINOR when + registering availability handlers. +- Fixed initial events on unsubscription +- Improved dispatcher handling for blocking calls +- Crashed applications are now automatically unsubscribed + +v2.5.2 +- Fixed deadlock and crashes +- Prevent race of initial attributes +- Allow incomplete application configurations +- Unit test timeouts increased to avoid failures on (slow) build servers + +v2.5.1 +- Removed payload size limit. By default messages with an arbitrary length can + now be sent locally and via TCP. The payload-sizes configuration file array is + now used to limit the payload size for the specified endpoints instead of + increasing it. There are two new configuration file parameters: + - max-payload-size-local: limit maximum allowed payload size for node internal + communication. + - buffer-shrink-threshold: variable to control buffer memory deallocation + after big messages have been processed. For more information see the + vsomeipUserGuide. +- Fixed cleanup of endpoints for subscriptions using an exclusive proxy + (selective) which unnecessarily increased the number of open file descriptors. +- Fixed assignment of predefined application IDs via autoconfiguration. +- Decouple start of routing manager from network availability. +- Made number of internal threads per application configurable. +- Postpone notify_one events sent from subscription handler to ensure correct + message order on receiver side. + +v2.5.0 +- Added notify-/notify_one-methods to enable flush control for notifications. +- Restructured configuration to be a separate module (preparation to enable + the usage of compiled configurations to speed-up startup) +- Added vSomeIP-Security: Socket authentication based on Linux-credentials + together with further security checks using configurable policies. +- Fixed pending subscriptions had not sent out if subscribing application + hosts the routing manager. +- Fixed crash in vsomeipd due to concurrent access when closing/shutdown socket. +- The service discovery now debounces newly offered service instances to avoid + sending out the offers of the same service instance with a too high frequency. + The default debounce time is set to 500ms. It can be changed via the new json + file parameter service-discovery/offer_debounce_time. + +v2.4.3 +- Fix receiving of UDP frames containing multiple SOME/IP messages via UDP from + external service instances + +v2.4.2 +- TCP connections for services no longer requested aren't reestablished anymore +- The minor version of a service instance is no longer considered when reporting + the service instance's availability +- Introduce new internal_services json file parameter to define the internal + service instances. This parameter can be used to control the sending behaviour + for find service entries +- Fixed event processing if service and client shared the same application +- Incoming find service entries with unicast flag set to 0 are now replied with + a unicast offer service message instead of a multicast offer service message. +- application::stop() now blocks until the shutdown has finished completely + +v2.4.1 +- Extended number of endpoints that can be referenced from entries array in + service discovery messages +- Remove DLT contexts on application shutdown +- Avoid initialization of vsomeip-applications if the maximum number of + applications (client identifiers) has been reached +- Prevent sending of OfferService entry as a reply to FindService message for + internal services +- Fixed deregistration of vsomeip-applications that became unresponsive +- Fixed loop in endpoints causing high load during shutdown of vsomeip + applications +- Fixed loop in endpoints causing temporary high load if other devices become + unavailable without deregistering + +v2.4.0 +- Disabled tracing SOME/IP-SD messages by default. Set "tracing/sd_enable" + switch to "true" to enable it. +- Trace notification events once instead of per target. + +v2.3.5 +- Fix TTL in Subscribe Eventgroup Entries + +v2.3.4 +- Exhaust client id range before reuse +- Provide public interface to ask for available instances + +v2.3.3 +- Added -q/--quiet switch to the daemon to allow it to be started without + DLT logging +- Fix event caching in routing manager + +v2.3.2 +- Fix client deregistration during the client registration +- Fix handling of pending commands during registration + +v2.3.1 +- Fix shutdown crashes (logger & application shutdown) +- Fix race condition in client identifier configuration +- Fix vsomeipd crash +- Fixed handling of notifications (compliance) + +v2.3.0 +- Extend the API to force field notifications +- Implemented cyclic updated for events/fields +- Implemented epsilon updates (the used can provide a function to decide + whether or not a value update shall be considered as a change) +- Fixed lifecycle: Wait acknowledge of de/register application +- Periodically log version information +- Avoid (shadow) event registrations for services only offered locally +- Fixed determination of routing manager host in case auto-configuration + fails +- Removed initial flag from internal message format +- Fixed calling of registered message handlers for cases where wildcards + were used during registration. +- Fixed availability reporting of reliable (TCP) remote services offered + on the same port + +v2.2.4 +- Set default log level to DEBUG +- Improved segmentation of service discovery messages +- Fixed a race condition during subscriptions + +v2.2.3 +- Ensure service discovery messages to not exceed maximum packet size + +v2.2.2 +- Ensure multicast messages are sent by the network adapter that is configured + to be used for unicasts instead of relying on the configured routes + +v2.2.1 +- Backward compatibility fixes + +v2.2.0 +- Implemented Peer-to-Peer data exchange for notifications +- Fixed handling of minor version during service discovery +- Made initialization of application objects reentrant +- Routing manager proxies now reconnect to the routing manager if the + connection got lost +- Auto-configuration supports multiple (different) configuration files +- The opening of TCP connections is no longer done without an explicit request +- Request No Respose messages are no longer answered in case of errors +- Notifications over IP were fixed + +v2.1.2 +- Ensure correct message order + +v2.1.1 +- Ensure SD FindService-messages are sent after client re-registration +- Corrected configuration of MagicCookies +- Make client ports configurable +- Implemented FindService message optimization +- Extended configuration consistency checks + +v2.1.0 +- Avoid duplicate notifications if a selective event is in more than one + eventgroup +- Ensure SD messages are sent from the SD port +- Ignore SD messages with wrong message identifier +- Accept unreliable subscription for eventgroups without configured multicast + address +- Reject subscriptions that contain invalid IP address or port +- Reject subscriptions for TCP if the connection is not established +- Exclude vsomeip_ctrl from default installation +- Only accept SD messages from SD port +- Acknowledge multiple subscriptions sent within the same message with a single + message +- Allow to specify an application specific DLT application +- Ensure correct ordering of availability notifications +- Automatically expire subscription based on the given TTL +- Do not include internal services in SD offer messages +- Consider all fields of SD subscribe messages +- Made the watchdog configurable +- Support destination address resolution on Windows (for reboot detection) +- Support auto-configuration (client identifiers, routing manager) on Windows + +v2.0.6 +- Diagnosis address can be configured at runtime + +v2.0.5 +- Fixed reboot detection behavior + +v2.0.4 +- Service Discovery now used configured Client ID prefixes (=DIAGNOSIS_ADDRESS) +- Reworked reboot detection (now based on the destination address) +- Aligned default TTL setting (was 5 in vsomeip and 0xFFFFFF in vsomeip-sd, now + its constently 0xFFFFFF) + +v2.0.3 +- Fixed shutdown and application re-registering + +v2.0.2 +- Fixed endpoint flushing +- Improved handling of Selective Broadcasts (CommonAPI) +- Trace connector was added +- Added reboot detection +- Reworked handling of TCP connections +- Support multiple multicast eventgroups per service +- Improved handling of multicasts +- Extended Service Discovery to send FindMessage messages for unknown services +- Support multiple SOME/IP messages in a single UDP datagram + +v2.0.1 +- Ensure Unicast flag is set in all Service Discovery messages +- Allow "local" as alias for unicast address in Magic Cookie configuration +- Correctly set layer 4 protocol in multicast options +- Increased robustness of deserialization of configuration options +- Fixed handling of unknown Service Discovery options + +v2.0.0 +- Buffer sizes were adapted to the transport protocols +- Added support for IPv6 multicast +- Improved handling of endpoints +- Report service state changes instead of service state to the application +- Set and process TTL field in Service Discovery to support detection of "lost" + services +- Support automatic configuration of local communication +- Added compile time variable DIAGNOSIS_ADDRESS (which maps to the high byte of + the SOME/IP client identifier) +- Configuration of events was moved from configuration file to API. +- Fixed routing of notication events. +- Increased robustness of configuration loader +- Changed default watchdog cycle from 1s to 5s +- Removed TTL arguments from public interface +- Allow Service Discovery to report non-SOME/IP services by setting the + configuration variable "protocol" +- Fixed serialization of major version in Eventgroup entries +- Magic Cookies are no longer forwarded to the routing manager but handled in + the receiving endpoint +- vsomeip daemon was added + +v1.3.0 +- Fixed SD library loading on Windows +- Changed cmake directory name (CMake --> cmake) +- Corrected check for multicast address in Service Discovery +- Added default setting for Service Discovery timings +- Ensure only local services are reported by the Service Discovery +- Fixed a crash in case of a wrong unicast address definition +- Protected forwarding of availability information +- Improved handling of notification events +- Added initial support for selective broadcasts (CommonAPI) +- Avoid deadlock when offering services +- Correct handling of events +- Added initial support for managed interfaces (CommonAPI) + +v1.2.0 +- Added (optional) thread pool for distribution of messages to the application +- Made configuration of service groups optional (as it is unneeded in pure + client applications) +- Support specification of transportation mode (reliable (TCP) / unreliable + (UDP)) when creating messages +- Fixed internal distribution of notication events +- Block messages that are received on the wrong port +- Fixed deregistration of local clients +- Fixed startup of applications that were started earlier than the routing + manager +- Resetting all events of a service if it becomes unavailable (to ensure initial + events are sent when it becomes available again) +- Ensure consistency of version information +- Fixed Service Discovery state machine + +v1.1.0 +- Local communication in multiprocessor environments was fixed +- Runtime access was changed from raw to shared pointer +- vsomeip logger is used whereever possible (replacing std::cerr calls) +- Ensure the logger is not deleted before issueing tha last log message when + shutting down +- Fixed shutdown crash by checking the existence of endpoint host before + accessing it +- Routing info processing in case of multiple instances of the same service + was fixed +- Support for local communication on Windows was added diff --git a/lib/libsomeip-c/vsomeip-3.5.1/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/CMakeLists.txt new file mode 100644 index 00000000000..7eabb3a81bb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/CMakeLists.txt @@ -0,0 +1,686 @@ +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required (VERSION 3.13) +project (vsomeip) + +set (VSOMEIP_NAME vsomeip3) +set (VSOMEIP_COMPAT_NAME vsomeip) + +set (VSOMEIP_MAJOR_VERSION 3) +set (VSOMEIP_MINOR_VERSION 5) +set (VSOMEIP_PATCH_VERSION 1) +set (VSOMEIP_HOTFIX_VERSION 0) + +set (VSOMEIP_VERSION ${VSOMEIP_MAJOR_VERSION}.${VSOMEIP_MINOR_VERSION}.${VSOMEIP_PATCH_VERSION}) +set (PACKAGE_VERSION ${VSOMEIP_VERSION}) # Used in documentation/doxygen.in +set (CMAKE_VERBOSE_MAKEFILE off) + +if (NOT GTEST_ROOT) + if (DEFINED ENV{GTEST_ROOT}) + set(GTEST_ROOT $ENV{GTEST_ROOT}) + else() + set(GTEST_ROOT "n/a" CACHE STRING "Path to root folder of googletest. Must be set for building the tests.") + endif() +endif() + +################################################################################################### +# see http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file +################################################################################################### + +# Offer the user the choice of overriding the installation directories +set (INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set (INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set (INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +if (WIN32 AND NOT CYGWIN) + set (DEF_INSTALL_CMAKE_DIR CMake) +else () + set (DEF_INSTALL_CMAKE_DIR lib/cmake/${VSOMEIP_NAME}) +endif () + +set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") + +# Make relative paths absolute (needed later on) +foreach (p LIB BIN INCLUDE CMAKE) + set (var INSTALL_${p}_DIR) + if (NOT IS_ABSOLUTE "${${var}}") + set (ABSOLUTE_${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") # Add all targets to the build-tree export set + endif () +endforeach () + +################################################################################################### +# Set a default build type if none was specified +set(default_build_type "RelWithDebInfo") +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +set(CMAKE_CXX_STANDARD 17) + +# OS +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(DL_LIBRARY "dl") + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # This is only relevant for GCC and causes warnings on Clang + set(EXPORTSYMBOLS "-Wl,-export-dynamic -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/exportmap.gcc") + set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -pie -Wno-tsan -Wl,-z,relro,-z,now") +endif() + + set(NO_DEPRECATED "") + set(OPTIMIZE "") + if(NOT DEFINED _FORTIFY_SOURCE) + set(_FORTIFY_SOURCE 2) + endif() + set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -D_GLIBCXX_USE_NANOSLEEP -pthread -O -Wall -Wextra -Wformat -Wformat-security -Wconversion -fexceptions -fstrict-aliasing -fstack-protector-strong -fasynchronous-unwind-tables -fno-omit-frame-pointer -D_FORTIFY_SOURCE=${_FORTIFY_SOURCE} -Wformat -Wformat-security -Wpedantic -Werror -fPIE") + + # force all use of std::mutex and std::recursive_mutex to use runtime init + # instead of static initialization so mutexes can be hooked to enable PI as needed + add_definitions(-D_GTHREAD_USE_MUTEX_INIT_FUNC -D_GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC) +endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + +if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(DL_LIBRARY "") + set(EXPORTSYMBOLS "") + set(NO_DEPRECATED "-Wno-deprecated") + set(OPTIMIZE "") + set(OS_CXX_FLAGS "-pthread") +endif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + +############################################My lib link flags#################################### +# Options +################################################################################ + +# DLT +if (DISABLE_DLT) +set (VSOMEIP_ENABLE_DLT 0) +else () +set (VSOMEIP_ENABLE_DLT 1) +endif () + +# Signal handling +if (ENABLE_SIGNAL_HANDLING) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_ENABLE_SIGNAL_HANDLING") +endif () + +# Event caching +if (ENABLE_DEFAULT_EVENT_CACHING) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_ENABLE_DEFAULT_EVENT_CACHING") +endif () + +if (NOT MSVC) + # Sanitizers + if (ENABLE_UNDEFINED_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + endif () + + if (ENABLE_THREAD_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + endif () + + if (ENABLE_LEAK_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak") + endif () + + if (ENABLE_ADDRESS_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + endif () + + if (ENABLE_PROFILING) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + endif () + + # Valgrind + find_program(VALGRIND "valgrind") + if (VALGRIND) + if (DEFINED VALGRIND_TYPE AND NOT VALGRIND_TYPE STREQUAL "") + set(TEST_ENTRYPOINT ${VALGRIND} --tool=${VALGRIND_TYPE}) + endif () + + if (VALGRIND_TYPE STREQUAL "helgrind") + set(TEST_ENTRYPOINT ${TEST_ENTRYPOINT} --suppressions=${VALGRIND_SUPPRESS_FILE} --gen-suppressions=all --log-file=${VALGRIND_LOGS_DIR}/test_name.out) + endif () + + if (VALGRIND_TYPE STREQUAL "massif") + set(TEST_ENTRYPOINT ${TEST_ENTRYPOINT} --massif-out-file=${VALGRIND_LOGS_DIR}/test_name.out) + endif () + + if (VALGRIND_TYPE STREQUAL "memcheck") + set(TEST_ENTRYPOINT ${TEST_ENTRYPOINT} --leak-check=yes --suppressions=${VALGRIND_SUPPRESS_FILE} --log-file=${VALGRIND_LOGS_DIR}/test_name.out) + endif () + endif () +endif (NOT MSVC) + +# Compatibility +if (ENABLE_COMPAT) +set (VSOMEIP_ENABLE_COMPAT 1) +else () +set (VSOMEIP_ENABLE_COMPAT 0) +endif () + +# Multiple routing managers +if (ENABLE_MULTIPLE_ROUTING_MANAGERS) +set (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS 1) +else () +set (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS 0) +endif () + +# Security / Policy handling +if (DISABLE_SECURITY) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_DISABLE_SECURITY") +endif () + +# Suppress deprecation warnings for vSomeIP interfaces +add_definitions(-DVSOMEIP_INTERNAL_SUPPRESS_DEPRECATED) + +################################################################################ +# Dependencies +################################################################################ + +# Threads +find_package(Threads REQUIRED) + +# Boost +find_package( Boost 1.66 COMPONENTS system thread filesystem REQUIRED ) +if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + include_directories(${Boost_INCLUDE_DIR} ) +else() + include_directories(SYSTEM ${Boost_INCLUDE_DIR} ) +endif() + +if(Boost_FOUND) + if(Boost_LIBRARY_DIR) + MESSAGE( STATUS "Boost_LIBRARY_DIR not empty using it: ${Boost_LIBRARY_DIR}" ) + else() + if(BOOST_LIBRARYDIR) + MESSAGE( STATUS "Boost_LIBRARY_DIR empty but BOOST_LIBRARYDIR is set setting Boost_LIBRARY_DIR to: ${BOOST_LIBRARYDIR}" ) + set(Boost_LIBRARY_DIR ${BOOST_LIBRARYDIR}) + endif() + endif() +else() + MESSAGE( STATUS "Boost was not found!") +endif() + +# cmake 3.15 introduced a new variable and a new format for the old one +if (DEFINED Boost_VERSION_MACRO) + set(VSOMEIP_BOOST_VERSION ${Boost_VERSION_MACRO}) +else() + set(VSOMEIP_BOOST_VERSION ${Boost_VERSION}) +endif() + +message( STATUS "Using boost version: ${VSOMEIP_BOOST_VERSION}" ) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_BOOST_VERSION=${VSOMEIP_BOOST_VERSION}") + +find_package(PkgConfig) + +# DLT +if(VSOMEIP_ENABLE_DLT EQUAL 1) +pkg_check_modules(DLT "automotive-dlt >= 2.11") +if(DLT_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DLT") +endif(DLT_FOUND) +endif() + +# SystemD +pkg_check_modules(SystemD "libsystemd") + +if(NOT SystemD_FOUND) +MESSAGE( STATUS "Systemd was not found, watchdog disabled!") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITHOUT_SYSTEMD") +endif(NOT SystemD_FOUND) + +# Multiple routing managers +if (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS EQUAL 1) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS") +endif () + +################################################################################ +# Directories +################################################################################ + +include_directories( + interface +) + +include_directories(SYSTEM + ${DLT_INCLUDE_DIRS} +) + +link_directories( + ${DLT_LIBDIR} +) + +if (${VSOMEIP_HOTFIX_VERSION} EQUAL 0) +add_definitions(-DVSOMEIP_VERSION="${VSOMEIP_VERSION}") +else() +add_definitions(-DVSOMEIP_VERSION="${VSOMEIP_VERSION}.${VSOMEIP_HOTFIX_VERSION}") +endif() + +if (MSVC) + message("using MSVC Compiler") + # add_definitions(-DVSOMEIP_DLL_COMPILATION) now it is controlled per target + SET(BOOST_WINDOWS_VERSION "0x600" CACHE STRING "Set the same Version as the Version with which Boost was built, otherwise there will be errors. (normaly 0x600 is for Windows 7 and 0x501 is for Windows XP)") + # Disable warning C4250 since it warns that the compiler is correctly following the C++ Standard. It's a "We-Are-Doing-Things-By-The-Book" notice, not a real warning. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -D_WIN32 -DBOOST_ASIO_DISABLE_IOCP /EHsc /wd4250") + set(USE_RT "") + link_directories(${Boost_LIBRARY_DIR_DEBUG}) + add_compile_options(/MD$<$<CONFIG:Debug>:d>) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + set(USE_RT "") +else() + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OS_CXX_FLAGS} -g ${OPTIMIZE} ${NO_DEPRECATED} ${EXPORTSYMBOLS}") + set(USE_RT "rt") +endif() + +################################################################################ +# Configuration library +################################################################################ +file(GLOB ${VSOMEIP_NAME}-cfg_SRC + "implementation/configuration/src/*.cpp" +) +list(SORT ${VSOMEIP_NAME}-cfg_SRC) +if (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS EQUAL 0) + add_library(${VSOMEIP_NAME}-cfg SHARED ${${VSOMEIP_NAME}-cfg_SRC}) + set_target_properties (${VSOMEIP_NAME}-cfg PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION}) + target_compile_features(${VSOMEIP_NAME}-cfg PRIVATE cxx_std_17) + if (MSVC) + set_target_properties(${VSOMEIP_NAME}-cfg PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") + endif() + + target_link_libraries(${VSOMEIP_NAME}-cfg ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES}) +endif () + +################################################################################ +# Base library +################################################################################ +file(GLOB ${VSOMEIP_NAME}_SRC + "implementation/endpoints/src/*.cpp" + "implementation/logger/src/*.cpp" + "implementation/tracing/src/*.cpp" + "implementation/message/src/*.cpp" + "implementation/plugin/src/*.cpp" + "implementation/protocol/src/*.cpp" + "implementation/routing/src/*.cpp" + "implementation/runtime/src/*.cpp" + "implementation/security/src/*.cpp" + "implementation/utility/src/*.cpp" +) +if (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS EQUAL 1) +list(APPEND ${VSOMEIP_NAME}_SRC "implementation/configuration/src/configuration_impl.cpp") +endif() + +if (WIN32) +list(FILTER ${VSOMEIP_NAME}_SRC EXCLUDE REGEX ".*uds.*") +endif() + +list(SORT ${VSOMEIP_NAME}_SRC) + +add_library(${VSOMEIP_NAME} SHARED ${${VSOMEIP_NAME}_SRC}) +set_target_properties (${VSOMEIP_NAME} PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION}) +target_compile_features(${VSOMEIP_NAME} PRIVATE cxx_std_17) +if (MSVC) + set_target_properties(${VSOMEIP_NAME} PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION") + set_target_properties(${VSOMEIP_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) +else () + set_target_properties(${VSOMEIP_NAME} PROPERTIES LINK_FLAGS "-Wl,-wrap,socket -Wl,-wrap,accept -Wl,-wrap,open") +endif () +target_include_directories(${VSOMEIP_NAME} INTERFACE + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/interface> + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}> + $<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>) +# PRIVATE means the listed libraries won't be included in the "link interface", +# meaning the exported ${VSOMEIP_NAME}Targets.cmake targets won't try to link against +# them (which shouldn't be required). ${Boost_LIBRARIES} includes absolute +# build host paths as of writing, which also makes this important as it breaks +# the build. +target_link_libraries(${VSOMEIP_NAME} PRIVATE ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${DLT_LIBRARIES} ${SystemD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + +if(NOT WIN32) + target_link_options(${VSOMEIP_NAME} PRIVATE "LINKER:-as-needed") +endif() + +################################################################################ +# Service Discovery library +################################################################################ +file(GLOB ${VSOMEIP_NAME}-sd_SRC + "implementation/service_discovery/src/*.cpp" +) +list(SORT ${VSOMEIP_NAME}-sd_SRC) + +add_library(${VSOMEIP_NAME}-sd SHARED ${${VSOMEIP_NAME}-sd_SRC}) +target_compile_features(${VSOMEIP_NAME}-sd PRIVATE cxx_std_17) +set_target_properties (${VSOMEIP_NAME}-sd PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION}) +if (MSVC) + set_target_properties(${VSOMEIP_NAME}-sd PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") +endif () + +target_link_libraries(${VSOMEIP_NAME}-sd ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + + +################################################################################ +# E2E library +################################################################################ +file(GLOB_RECURSE ${VSOMEIP_NAME}-e2e_SRC + "implementation/e2e_protection/src/*.cpp" +) +list(SORT ${VSOMEIP_NAME}-e2e_SRC) + +add_library(${VSOMEIP_NAME}-e2e SHARED ${${VSOMEIP_NAME}-e2e_SRC}) +target_compile_features(${VSOMEIP_NAME}-e2e PRIVATE cxx_std_17) +set_target_properties (${VSOMEIP_NAME}-e2e PROPERTIES VERSION ${VSOMEIP_VERSION} SOVERSION ${VSOMEIP_MAJOR_VERSION}) +if (MSVC) + set_target_properties(${VSOMEIP_NAME}-e2e PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") +endif () + +target_link_libraries(${VSOMEIP_NAME}-e2e ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES}) + +if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + target_link_directories(${VSOMEIP_NAME} PUBLIC "${QNX_TARGET}/${CPUVARDIR}/io-sock/lib") + target_link_libraries(${VSOMEIP_NAME}-e2e socket) + target_link_libraries(${VSOMEIP_NAME}-cfg socket) + target_link_libraries(${VSOMEIP_NAME}-sd socket) + target_link_libraries(${VSOMEIP_NAME} PRIVATE socket) +endif() +################################################################################ +# Compatibility library +################################################################################ +if (VSOMEIP_ENABLE_COMPAT EQUAL 1) +set (VSOMEIP_COMPAT_MAJOR_VERSION 2) +set (VSOMEIP_COMPAT_VERSION ${VSOMEIP_COMPAT_MAJOR_VERSION}.99.99) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_ENABLE_COMPAT") + +file(GLOB_RECURSE ${VSOMEIP_COMPAT_NAME}_SRC + "implementation/compat/logging/src/*.cpp" + "implementation/compat/message/src/*.cpp" + "implementation/compat/runtime/src/*.cpp" +) +list(SORT ${VSOMEIP_COMPAT_NAME}_SRC) + +add_library(${VSOMEIP_COMPAT_NAME} SHARED ${${VSOMEIP_COMPAT_NAME}_SRC}) +target_compile_features(${VSOMEIP_COMPAT_NAME} PRIVATE cxx_std_17) +set_target_properties (${VSOMEIP_COMPAT_NAME} PROPERTIES VERSION ${VSOMEIP_COMPAT_VERSION} SOVERSION ${VSOMEIP_COMPAT_MAJOR_VERSION}) +if (MSVC) + set_target_properties(${VSOMEIP_COMPAT_NAME} PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION_PLUGIN") +endif () + +target_include_directories( + ${VSOMEIP_COMPAT_NAME} + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/interface/compat> + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> # for generated files in build mode + $<INSTALL_INTERFACE:include/compat> # for clients in install mode +) +target_link_libraries(${VSOMEIP_COMPAT_NAME} PRIVATE ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${SystemD_LIBRARIES}) + +endif () + +################################################################################ +# Configuration files +################################################################################ +set(EXAMPLE_CONFIG_FILES + "config/vsomeip.json" + "config/vsomeip-local.json" + "config/vsomeip-tcp-client.json" + "config/vsomeip-tcp-service.json" + "config/vsomeip-udp-client.json" + "config/vsomeip-udp-service.json" +) + +################################################################################ +# Configuration parameters +################################################################################ +if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + set (VSOMEIP_BASE_PATH "/var") +else() + set (VSOMEIP_BASE_PATH "/tmp") +endif() +if (BASE_PATH) +set (VSOMEIP_BASE_PATH ${BASE_PATH}) +endif () + +set (VSOMEIP_DIAGNOSIS_ADDRESS "0x01") +if (DIAGNOSIS_ADDRESS) +set (VSOMEIP_DIAGNOSIS_ADDRESS ${DIAGNOSIS_ADDRESS}) +endif () + +set (VSOMEIP_UNICAST_ADDRESS "127.0.0.1") +if (UNICAST_ADDRESS) +set (VSOMEIP_UNICAST_ADDRESS ${UNICAST_ADDRESS}) +endif () + +set (VSOMEIP_ROUTING_READY_MESSAGE "SOME/IP routing ready.") +if (ROUTING_READY_MESSAGE) +set (VSOMEIP_ROUTING_READY_MESSAGE ${ROUTING_READY_MESSAGE}) +endif () + +set (VSOMEIP_LOCAL_TCP_PORT_WAIT_TIME 100) +if (LOCAL_TCP_PORT_WAIT_TIME) +set (VSOMEIP_LOCAL_TCP_PORT_WAIT_TIME ${LOCAL_TCP_PORT_WAIT_TIME}) +endif () + +set (VSOMEIP_LOCAL_TCP_PORT_MAX_WAIT_TIME 10000) +if (LOCAL_TCP_PORT_MAX_WAIT_TIME) +if (${LOCAL_TCP_PORT_MAX_WAIT_TIME} GREATER ${LOCAL_TCP_PORT_WAIT_TIME}) +set (VSOMEIP_LOCAL_TCP_PORT_MAX_WAIT_TIME ${LOCAL_TCP_PORT_MAX_WAIT_TIME}) +else () +set (VSOMEIP_LOCAL_TCP_PORT_MAX_WAIT_TIME ${LOCAL_TCP_PORT_WAIT_TIME}) +endif () +endif () + +set(DEFAULT_CONFIGURATION_FOLDER "/etc/vsomeip" CACHE PATH "Default configuration folder") +message(STATUS "Default configuration folder: ${DEFAULT_CONFIGURATION_FOLDER}") + +set(DEFAULT_CONFIGURATION_FILE "/etc/vsomeip.json" CACHE FILEPATH "Default configuration file") +message(STATUS "Default configuration file: ${DEFAULT_CONFIGURATION_FILE}") + +message("Predefined base path: ${VSOMEIP_BASE_PATH}") +message("Predefined unicast address: ${VSOMEIP_UNICAST_ADDRESS}") +message("Predefined diagnosis address: ${VSOMEIP_DIAGNOSIS_ADDRESS}") +message("Predefined wait times for internal communication ports (TCP):\ + ${VSOMEIP_LOCAL_TCP_PORT_WAIT_TIME}\ + (max=${VSOMEIP_LOCAL_TCP_PORT_MAX_WAIT_TIME})") + +################################################################################ +# Installation +################################################################################ +set(INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/interface/vsomeip") + +file (GLOB_RECURSE vsomeip_INCLUDE RELATIVE ${INCLUDE_PATH} "interface/*.h*" ) +list (SORT vsomeip_INCLUDE) + +foreach ( file ${vsomeip_INCLUDE} ) + get_filename_component( dir ${file} DIRECTORY ) + install( FILES "${INCLUDE_PATH}/${file}" DESTINATION "${INSTALL_INCLUDE_DIR}/vsomeip/${dir}" COMPONENT dev) +endforeach() + +install ( + TARGETS ${VSOMEIP_NAME} + # IMPORTANT: Add the vsomeip library to the "export-set" + EXPORT ${VSOMEIP_NAME}Targets + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + COMPONENT dev +) + +install ( + TARGETS ${VSOMEIP_NAME}-e2e + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) + +if (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS EQUAL 0) +install ( + TARGETS ${VSOMEIP_NAME}-cfg + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) +endif () + +install ( + TARGETS ${VSOMEIP_NAME}-sd + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) + +if (VSOMEIP_ENABLE_COMPAT EQUAL 1) +install ( + TARGETS ${VSOMEIP_COMPAT_NAME} + EXPORT vsomeipTargets + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) + +export (TARGETS ${VSOMEIP_COMPAT_NAME} FILE "${PROJECT_BINARY_DIR}/vsomeipTargets.cmake") +export (PACKAGE ${VSOMEIP_COMPAT_NAME}) + +configure_file (vsomeipConfig.cmake.in "${PROJECT_BINARY_DIR}/vsomeipConfig.cmake" @ONLY) +configure_file (vsomeipConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/vsomeipConfigVersion.cmake" @ONLY) + +set (COMPAT_INSTALL_CMAKE_DIR "lib/cmake/${VSOMEIP_COMPAT_NAME}") + +install ( + EXPORT vsomeipTargets + DESTINATION "${COMPAT_INSTALL_CMAKE_DIR}" + COMPONENT dev +) + +install ( + FILES + "${PROJECT_BINARY_DIR}/vsomeipConfig.cmake" + "${PROJECT_BINARY_DIR}/vsomeipConfigVersion.cmake" + DESTINATION "${COMPAT_INSTALL_CMAKE_DIR}" + COMPONENT dev +) + +configure_file(vsomeip.pc.in ${PROJECT_BINARY_DIR}/vsomeip.pc @ONLY) +install(FILES ${PROJECT_BINARY_DIR}/vsomeip.pc DESTINATION lib/pkgconfig) + +endif () + +install ( + FILES ${EXAMPLE_CONFIG_FILES} DESTINATION etc/vsomeip COMPONENT config +) + +# Add all targets to the build-tree export set +export (TARGETS ${VSOMEIP_NAME} FILE "${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}Targets.cmake") + +# Export the package for use from the build-tree +# (this registers the build-tree with a global CMake-registry) +export (PACKAGE ${VSOMEIP_NAME}) + +# Create the ${VSOMEIP_NAME}Config.cmake and ${VSOMEIP_NAME}ConfigVersion files +configure_file (${VSOMEIP_NAME}Config.cmake.in "${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}Config.cmake" @ONLY) +configure_file (${VSOMEIP_NAME}ConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}ConfigVersion.cmake" @ONLY) + +# configure internal.hpp for correct version number +configure_file ( + "${PROJECT_SOURCE_DIR}/implementation/configuration/include/internal.hpp.in" + "${PROJECT_SOURCE_DIR}/implementation/configuration/include/internal.hpp" +) + +# Install the ${VSOMEIP_NAME}Config.cmake and ${VSOMEIP_NAME}ConfigVersion.cmake +install ( + FILES + "${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}ConfigVersion.cmake" + DESTINATION "${INSTALL_CMAKE_DIR}" + COMPONENT dev +) + +# Install the export set for use with the install-tree +install ( + EXPORT ${VSOMEIP_NAME}Targets + DESTINATION "${INSTALL_CMAKE_DIR}" + COMPONENT dev +) + +############################################################################## +# build documentation +############################################################################## +add_custom_target(doc) + +find_package(Doxygen) +if (NOT DOXYGEN_FOUND) + message(WARNING "Doxygen is not installed. Documentation can not be built.") +else() + # set configuration variables for doxygen.in + set(PROJECT "vsomeip") + set(DOCDIR documentation) + set(SRCDIR .) + set(GENERATE_HTML YES) + set(GENERATE_HTMLHELP NO) + set(GENERATE_CHI NO) + set(GENERATE_LATEX NO) + set(GENERATE_PDF NO) + set(GENERATE_RTF NO) + set(GENERATE_MAN NO) + set(GENERATE_XML NO) + set(HAVE_DOT YES) + + if(HAVE_DOT) + # Note: the @DOT_PATH@ variable won't be used in doxygen.in as doxygen + # somehow manages to strip the last slash from the path and therfore no + # graphs are generated. Therefore dot should be available in your $PATH + FIND_PROGRAM(DOT_PATH dot) + if ("${DOT_PATH}" STREQUAL "DOT_PATH-NOTFOUND") + message(WARNING "dot (graphviz) is not installed. Graphs in documentation can't be generated.") + else() + message("dot found") + endif() + endif() + + configure_file(documentation/doxygen.in ${PROJECT_BINARY_DIR}/Doxyfile @ONLY) + add_custom_target(doxygen-doc + COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile + SOURCES ${PROJECT_BINARY_DIR}/Doxyfile) + + add_dependencies(doc doxygen-doc) +endif() + +############################################################################## +# create pkg-config file +if(NOT WIN32) + configure_file(${VSOMEIP_NAME}.pc.in ${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}.pc @ONLY) + install(FILES ${PROJECT_BINARY_DIR}/${VSOMEIP_NAME}.pc DESTINATION lib/pkgconfig) +endif() + +############################################################################## +# build routing manager daemon (Non-Windows only) +if (NOT MSVC) +add_subdirectory( examples/routingmanagerd ) +endif() + +# build tools +add_custom_target( tools ) +add_subdirectory( tools/vsomeip_ctrl ) + +# build examples +add_custom_target( examples ) +add_subdirectory( examples EXCLUDE_FROM_ALL ) + +############################################################################## +# add test directory +enable_testing() + +add_subdirectory( test EXCLUDE_FROM_ALL ) + +if (${CMAKE_SYSTEM_NAME} MATCHES "QNX") + install(DIRECTORY ${PROJECT_BINARY_DIR}/test/ + DESTINATION bin/vsomeip_tests/test + PATTERN "CMakeFiles" EXCLUDE + PATTERN "*.cmake" EXCLUDE + PATTERN "Makefile" EXCLUDE + ) + + install(FILES ${PROJECT_BINARY_DIR}/examples/routingmanagerd/routingmanagerd + DESTINATION bin/vsomeip_tests/examples/routingmanagerd) +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/CMakePresets.json b/lib/libsomeip-c/vsomeip-3.5.1/CMakePresets.json new file mode 100644 index 00000000000..f2056bf01cb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/CMakePresets.json @@ -0,0 +1,74 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 13 + }, + "configurePresets": [ + { + "name": "ci-network-tests", + "displayName": "Network tests (CI)", + "description": "Preset for network tests on CI", + "generator": "Ninja", + "binaryDir": "/home/build", + "cacheVariables": { + "CMAKE_CXX_FLAGS_INIT": { + "type": "STRING", + "value": "--coverage -Wno-error=tsan" + }, + "TEST_IP_SLAVE_SECOND": { + "type": "STRING", + "value": "$penv{IP_SLAVE_2ND}" + }, + "TEST_GID": { + "type": "STRING", + "value": "0" + }, + "TEST_UID": { + "type": "STRING", + "value": "0" + } + }, + "environment": { + "GTEST_ROOT": "/usr/src/googletest" + } + } + ], + "buildPresets": [ + { + "name": "ci-network-tests", + "displayName": "Network tests (CI)", + "description": "Preset for network tests on CI", + "configurePreset": "ci-network-tests", + "targets": "build_network_tests" + } + ], + "testPresets": [ + { + "name": "ci-network-tests", + "displayName": "Network tests (CI)", + "description": "Preset for network tests on CI", + "environment": { + "LD_LIBRARY_PATH": "/home/build", + "LXC_TEST_MASTER_IP": "master", + "LXC_TEST_SLAVE_IP": "slave", + "TSAN_OPTIONS": "suppressions=${sourceDir}/test/tsan-suppressions.txt", + "USE_LXC_TEST": "1" + }, + "configurePreset": "ci-network-tests", + "output": { + "maxFailedTestOutputSize": 1e6, + "maxPassedTestOutputSize": 1e6, + "outputOnFailure": true + }, + "execution": { + "timeout": 150 + }, + "filter": { + "exclude": { + "name": "^unit_" + } + } + } + ] +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/CONTRIBUTING.md b/lib/libsomeip-c/vsomeip-3.5.1/CONTRIBUTING.md new file mode 100644 index 00000000000..d0a1b6acc5a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/CONTRIBUTING.md @@ -0,0 +1,203 @@ +# Contributing to vsomeip-lib + +All types of contributions are encouraged and valued. + +## Did you find a bug? + +- **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/COVESA/vsomeip/issues). + +- If you cannot find an existing open issue addressing the problem, feel free to create a new one [here](https://github.com/COVESA/vsomeip/issues/new). Make sure to provide a descriptive **title, a clear explanation of the issue, relevant information**, and if possible, include a code sample or a test case demonstrating the expected behavior that is not occurring. + +## Styleguides + +We prioritize consistency and maintainability in our code bases. To achieve this, we have established comprehensive coding standards encompassing general style guidelines and specific configurations for Clang-Format integration. + +Explore the [Table of Contents](#table-of-contents) to discover various paths for assistance and comprehensive insights into our coding standards. + +### Table of Contents + +- [General Guidelines](#general-guidelines) + +- [Naming Conventions](#naming-conventions) + +- [Clang Format Integration](#clang-format-integration) + + - [Based Style](#based-style) + + - [Standard](#standard) + + - [Clang-Format Customization](#clang-format-customization) + + - [How to use Clang Format](#how-to-use-clang-format) + + - [Workflow Summary](#workflow-summary) + +- [Showcase of good and bad practice](#showcase-of-good-and-bad-practice) + +### General Guidelines + +Before submitting a pull request, please ensure that you adhere to the following coding guidelines. + +### Naming Conventions + +Maintaining a consistent naming convention enhances code readability and comprehension. Our naming conventions dictate the following: + - **Arguments:** Argument names should start with an underscore. + + - **Members:** Member variables should end with an underscore. + + - **Local Variables:** Local variables neither start nor end with an underscore. + + - **Static Variables:** Static variables should end with two underscores. + +### Clang Format Integration + +Incorporating Clang Format into our projects is integral to ensuring uniform and readable code formatting. Clang Format is a powerful tool that automatically formats C, C++, and Objective-C code based on predefined style guidelines. + +#### Based Style + +```yaml +BasedOnStyle: WebKit +``` +Our code style is based on the WebKit style, which is in turn influenced by the Qt style. + +Webkit style guidelines can be found here [Webkit.org](https://www.webkit.org/code-style-guidelines/) + +#### Standard + +```yaml +Standard: c++17 +``` +The C++ standard to be used, in this case, C++17. + +Below is the configuration option used in our Clang Format setup: + +#### Clang-Format Customization + +```yaml +BasedOnStyle: WebKit +Standard: c++17 +ColumnLimit: 100 +PointerAlignment: Left +SpaceAfterTemplateKeyword: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: true +NamespaceIndentation: None +IndentPPDirectives: AfterHash +AlignAfterOpenBracket: true +AlwaysBreakTemplateDeclarations: true +AllowShortFunctionsOnASingleLine: Inline +SortIncludes: false +BreakConstructorInitializers: AfterColon +``` + +#### How to use Clang Format + +Formatting your code using Clang Format is seamlessly integrated into the development workflow through [pre-commit-hooks](https://github.com/pocc/pre-commit-hooks). Follow these steps to set it up: + +#### Step 1: Install `pre-commit` + +``` +pip install pre-commit +``` + +#### Step 2: Navigate to the project's root directory + +``` +cd vsomeip-lib +``` + +#### Step 3: Install the pre-commit hook + +``` +pre-commit install +``` + +Now, every time you commit staged changes, Clang Format will automatically be invoked to format your code. This is achieved through the pre-commit hook. + +#### Workflow Summary + +1. **Make your code changes** + - Implement the desired changes in your code. + +2. **Stage the changes using `git add`** + - Use `git add` to stage the modifications you want to commit. + +3. **Commit changes with `git commit`** + - When you run `git commit`, Clang Format will automatically be applied to the staged changes before the commit is finalized. + +This seamless integration ensures consistent code formatting as part of the development workflow. Developers can focus on writing code, and the pre-commit hook takes care of formatting during the commit process. + +### Showcase of good and bad practice + +This code snippet was taken from `vsomeip-lib/implementation/routing/src/routing_manager_impl.cpp `. + +#### Good Practice + +```c++ +void routing_manager_impl::init() { + routing_manager_base::init(ep_mgr_impl_); + if (configuration_->is_routing_enabled()) { + stub_ = std::make_shared<routing_manager_stub>(this, configuration_); + stub_->init(); + } else { + // Good Practice: Proper indentation and spacing. + VSOMEIP_INFO << "Internal message routing disabled!"; + } + // Good Practice: Proper spacing and indentation. + if (configuration_->is_sd_enabled()) { + // Good Practice: Proper spacing and alignment. + VSOMEIP_INFO << "Service Discovery enabled. Trying to load module."; + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY); + if (its_plugin) { + // Good Practice: Braces attached to the preceding line, consistent spacing. + VSOMEIP_INFO << "Service Discovery module loaded."; + discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin) + ->create_service_discovery(this, configuration_); + discovery_->init(); + } else { + // Good Practice: Proper indentation and spacing. + VSOMEIP_ERROR << "Service Discovery module could not be loaded!"; + std::exit(EXIT_FAILURE); + } + } +} +``` + +#### Bad Practice + +```c++ +void routing_manager_impl::init() +{ + routing_manager_base::init(ep_mgr_impl_); + // Bad Practice: Inconsistent indentation and brace placement. + if (configuration_-> is_routing_enabled()) + { + stub_ = std::make_shared<routing_manager_stub>(this, configuration_); + stub_->init(); + } + else + { + // Bad Practice: Inconsistent indentation and lack of space after binary operators. + VSOMEIP_INFO + << "Internal message routing disabled!"; + } + // Bad Practice: Lack of proper spacing and alignment. + if (configuration_->is_sd_enabled()) + { + // Bad Practice: Inconsistent indentation and spacing. + VSOMEIP_INFO << "Service Discovery enabled. Trying to load module."; + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY); if (its_plugin) {VSOMEIP_INFO + << "Service Discovery module loaded."; + discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin)->create_service_discovery(this, configuration_);discovery_->init(); + } + else {VSOMEIP_ERROR + << "Service Discovery module could not be loaded!"; + std::exit(EXIT_FAILURE);} + } +} +``` diff --git a/lib/libsomeip-c/vsomeip-3.5.1/Dockerfile b/lib/libsomeip-c/vsomeip-3.5.1/Dockerfile new file mode 100644 index 00000000000..0f131fc0818 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:jammy +SHELL ["/bin/bash", "-xec"] +RUN export DEBIAN_FRONTEND=noninteractive;\ + apt-get update;\ + apt-get dist-upgrade --no-install-recommends --purge --yes\ + clang-12\ + cmake\ + g++\ + googletest\ + libbenchmark-dev\ + libboost-{{file,}system,thread}-dev\ + make\ + python3-pip\ + ;\ + apt-get autoremove --purge --yes;\ + apt-get clean;\ + pip3 install gcovr;\ + ln -s /usr/bin/clang-12 /usr/bin/clang;\ + ln -s /usr/bin/clang++-12 /usr/bin/clang++;\ + ln -s /usr/bin/lld-12 /usr/bin/lld;\ + ln -s /usr/bin/clang-tidy-12 /usr/bin/clang-tidy + +ENV GTEST_ROOT=/usr/src/googletest + +WORKDIR /home/source +VOLUME ["/home/source"] diff --git a/lib/libsomeip-c/vsomeip-3.5.1/LICENSE b/lib/libsomeip-c/vsomeip-3.5.1/LICENSE new file mode 100644 index 00000000000..a612ad9813b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/lib/libsomeip-c/vsomeip-3.5.1/README.md b/lib/libsomeip-c/vsomeip-3.5.1/README.md new file mode 100644 index 00000000000..908c9d6f464 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/README.md @@ -0,0 +1,118 @@ +### vSomeIP + +##### Copyright +Copyright (C) 2015-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + +##### License + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +##### Contributing Guidelines + +For comprehensive details on how to contribute effectively to the project, please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md) file. + +##### vsomeip Overview +---------------- +The vSomeIP stack implements the http://some-ip.com/ (Scalable service-Oriented +MiddlewarE over IP (SOME/IP)) protocol. The stack consists out of: + +* a shared library for SOME/IP (`libvsomeip3.so`) +* a shared library for SOME/IP's configuration module (`libvsomeip3-cfg.so`) +* a shared library for SOME/IP's service discovery (`libvsomeip3-sd.so`) +* a shared library for SOME/IP's E2E protection module (`libvsomeip3-e2e.so`) + +Optional: + +* a shared library for compatibility with vsomeip v2 (`libvsomeip.so`) + +##### Build Instructions for Linux + +###### Dependencies + +- A C++17 enabled compiler is needed. +- vSomeIP uses CMake as buildsystem. +- vSomeIP uses Boost >= 1.66.0: + +For the tests Google's test framework https://code.google.com/p/googletest/[gtest] is needed. +-- URL: https://googletest.googlecode.com/files/gtest-<version>.zip + +To build the documentation doxygen and graphviz are needed: +--`sudo apt-get install doxygen graphviz` + +###### Compilation + +For compilation call: + +```bash +mkdir build +cd build +cmake .. +make +``` + +To specify a installation directory (like `--prefix=` if you're used to autotools) call cmake like: +```bash +cmake -DCMAKE_INSTALL_PREFIX:PATH=$YOUR_PATH .. +make +make install +``` + +###### Compilation with predefined unicast and/or diagnosis address +To predefine the unicast address, call cmake like: +```bash +cmake -DUNICAST_ADDRESS=<YOUR IP ADDRESS> .. +``` + +To predefine the diagnosis address, call cmake like: +```bash +cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> .. +``` +The diagnosis address is a single byte value. + +###### Compilation with custom default configuration folder +To change the default configuration folder, call cmake like: +```bash +cmake -DDEFAULT_CONFIGURATION_FOLDER=<DEFAULT CONFIGURATION FOLDER> .. +``` +The default configuration folder is /etc/vsomeip. + +###### Compilation with custom default configuration file +To change the default configuration file, call cmake like: +```bash +cmake -DDEFAULT_CONFIGURATION_FILE=<DEFAULT CONFIGURATION FILE> .. +``` +The default configuration file is /etc/vsomeip.json. + +###### Compilation with signal handling + +To compile vSomeIP with signal handling (SIGINT/SIGTERM) enabled, call cmake like: +```bash +cmake -DENABLE_SIGNAL_HANDLING=1 .. +``` +In the default setting, the application has to take care of shutting down vSomeIP in case these signals are received. + + +##### Build Instructions for Android + +###### Dependencies + +- vSomeIP uses Boost >= 1.66. The boost libraries (system, thread and log) must be included in the Android source tree and integrated into the build process with an appropriate Android.bp file. + +###### Compilation + +In general for building the Android source tree the instructions found on the pages from the Android Open Source Project (AOSP) apply (https://source.android.com/setup/build/requirements). + +To integrate the vSomeIP library into the build process, the source code together with the Android.bp file has to be inserted into the Android source tree (by simply copying or by fetching with a custom platform manifest). +When building the Android source tree, the Android.bp file is automatically found and considered by the build system. + +In order that the vSomeIP library is also included in the Android image, the library has to be added to the PRODUCT_PACKAGES variable in one of a device/target specific makefile: + +``` +PRODUCT_PACKAGES += \ + libvsomeip \ + libvsomeip_cfg \ + libvsomeip_sd \ + libvsomeip_e2e \ +``` diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/Makefile new file mode 100644 index 00000000000..1f254004140 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/Makefile @@ -0,0 +1,8 @@ +LIST=OS +ifndef QRECURSE +QRECURSE=recurse.mk +ifdef QCONFIG +QRDIR=$(dir $(QCONFIG)) +endif +endif +include $(QRDIR)$(QRECURSE) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/common.mk b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/common.mk new file mode 100644 index 00000000000..c7905f68119 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/common.mk @@ -0,0 +1,114 @@ +ifndef QCONFIG +QCONFIG=qconfig.mk +endif +include $(QCONFIG) + +#where to install vsomeip: +#$(INSTALL_ROOT_$(OS)) is pointing to $QNX_TARGET +#by default, unless it was manually re-routed to +#a staging area by setting both INSTALL_ROOT_nto +#and USE_INSTALL_ROOT +VSOMEIP_INSTALL_ROOT ?= $(INSTALL_ROOT_$(OS)) + +#where to find the vsomeip external dependencies, such as Boost +VSOMEIP_EXTERNAL_DEPS_INSTALL ?= $(USE_ROOT_$(OS)) + +# Get version information from CMakeLists.txt +VSOMEIP_MAJOR_VERSION = $(word 3, $(shell bash -c "grep VSOMEIP_MAJOR_VERSION $(PROJECT_ROOT)/../CMakeLists.txt | head -1 | head -c-2")) +VSOMEIP_MINOR_VERSION = $(word 3, $(shell bash -c "grep VSOMEIP_MINOR_VERSION $(PROJECT_ROOT)/../CMakeLists.txt | head -1 | head -c-2")) +VSOMEIP_PATCH_VERSION = $(word 3, $(shell bash -c "grep VSOMEIP_PATCH_VERSION $(PROJECT_ROOT)/../CMakeLists.txt | head -1 | head -c-2")) + +#choose Release or Debug +CMAKE_BUILD_TYPE ?= Release + +#set the following to TRUE if you want to compile the vsomeip tests. +#If you do, make sure to set GTEST_ROOT to point to the google test library sources +GENERATE_TESTS ?= TRUE +TEST_IP_MASTER ?= XXX.XXX.XXX.XXX +TEST_IP_SLAVE ?= XXX.XXX.XXX.XXX + +#set the following to FALSE if generating .pinfo files is causing problems +GENERATE_PINFO_FILES ?= TRUE + +#override 'all' target to bypass the default QNX build system +ALL_DEPENDENCIES = vsomeip_all +.PHONY: vsomeip_all + +FLAGS += -g -D_QNX_SOURCE +LDFLAGS += -Wl,--build-id=md5 -lang-c++ -lsocket + +INCVPATH+=$(USE_ROOT_INCLUDE) +EXTRA_INCVPATH = $(USE_ROOT_INCLUDE)/io-sock +LIBVPATH=$(QNX_TARGET)/usr/lib +EXTRA_LIBVPATH = $(USE_ROOT_LIB)/io-sock + +CMAKE_ARGS = -DCMAKE_TOOLCHAIN_FILE=$(PROJECT_ROOT)/qnx.nto.toolchain.cmake \ + -DCMAKE_INSTALL_PREFIX=$(VSOMEIP_INSTALL_ROOT)/$(CPUVARDIR)/usr \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_NO_SYSTEM_FROM_IMPORTED=TRUE \ + -DVSOMEIP_EXTERNAL_DEPS_INSTALL=$(VSOMEIP_EXTERNAL_DEPS_INSTALL) \ + -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ + -DCMAKE_MODULE_PATH=$(PROJECT_ROOT) \ + -DEXTRA_CMAKE_C_FLAGS="$(FLAGS)" \ + -DEXTRA_CMAKE_CXX_FLAGS="$(FLAGS)" \ + -DEXTRA_CMAKE_LINKER_FLAGS="$(LDFLAGS)" \ + -DINSTALL_INCLUDE_DIR=$(VSOMEIP_INSTALL_ROOT)/usr/include \ + -DCPUVARDIR=$(CPUVARDIR) \ + -DGCC_VER=${GCC_VER} \ + -DVSOMEIP_INSTALL_ROUTINGMANAGERD=ON \ + -DDISABLE_DLT=y + +ifeq ($(GENERATE_TESTS), TRUE) +CMAKE_ARGS += -DENABLE_SIGNAL_HANDLING=1 \ + -DTEST_IP_MASTER=$(TEST_IP_MASTER) \ + -DTEST_IP_SLAVE=$(TEST_IP_SLAVE) +endif + +MAKE_ARGS ?= -j $(firstword $(JLEVEL) 4) + +define PINFO +endef +PINFO_STATE=Experimental +USEFILE= + +include $(MKFILES_ROOT)/qtargets.mk + +ifneq ($(wildcard $(foreach dir,$(LIBVPATH),$(dir)/libregex.so)),) + LDFLAGS += -lregex +endif + + +ifndef NO_TARGET_OVERRIDE +vsomeip_all: + @mkdir -p build + @cd build && cmake $(CMAKE_ARGS) ../../../../../ + @cd build && make all $(MAKE_ARGS) + @cd build && make build_tests $(MAKE_ARGS) + +install: vsomeip_all + @cd build && make install $(MAKE_ARGS) + @cd build && make build_tests install $(MAKE_ARGS) + +clean iclean spotless: + @rm -fr build + +endif + +#everything down below deals with the generation of the PINFO +#information for shared objects that is used by the QNX build +#infrastructure to embed metadata in the .so files, for example +#data and time, version number, description, etc. Metadata can +#be retrieved on the target by typing 'use -i <path to vsomeip .so file>'. +#this is optional: setting GENERATE_PINFO_FILES to FALSE will disable +#the insertion of metadata in .so files. +ifeq ($(GENERATE_PINFO_FILES), TRUE) +#the following rules are called by the cmake generated makefiles, +#in order to generate the .pinfo files for the shared libraries +%.so.$(VSOMEIP_MAJOR_VERSION).$(VSOMEIP_MINOR_VERSION).$(VSOMEIP_PATCH_VERSION): + $(ADD_PINFO) + $(ADD_USAGE) + +%vsomeipd: + $(ADD_PINFO) + $(ADD_USAGE) +endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/Makefile new file mode 100644 index 00000000000..0cc5eae2d76 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/Makefile @@ -0,0 +1,8 @@ +LIST=CPU +ifndef QRECURSE +QRECURSE=recurse.mk +ifdef QCONFIG +QRDIR=$(dir $(QCONFIG)) +endif +endif +include $(QRDIR)$(QRECURSE) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/Makefile new file mode 100644 index 00000000000..0e22650c04c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/Makefile @@ -0,0 +1,8 @@ +LIST=VARIANT +ifndef QRECURSE +QRECURSE=recurse.mk +ifdef QCONFIG +QRDIR=$(dir $(QCONFIG)) +endif +endif +include $(QRDIR)$(QRECURSE) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/le/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/le/Makefile new file mode 100644 index 00000000000..966eb3d39fa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/aarch64/le/Makefile @@ -0,0 +1,5 @@ +include ../../../common.mk + +CMAKE_ARGS += -DCMAKE_SYSTEM_PROCESSOR=aarch64 +FLAGS += $(VFLAG_le) $(CCVFLAG_le) +LDFLAGS += $(VFLAG_le) $(LDVFLAG_le) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/Makefile new file mode 100644 index 00000000000..0e22650c04c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/Makefile @@ -0,0 +1,8 @@ +LIST=VARIANT +ifndef QRECURSE +QRECURSE=recurse.mk +ifdef QCONFIG +QRDIR=$(dir $(QCONFIG)) +endif +endif +include $(QRDIR)$(QRECURSE) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/o/Makefile b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/o/Makefile new file mode 100644 index 00000000000..68ecccfaea4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/nto/x86_64/o/Makefile @@ -0,0 +1,3 @@ +include ../../../common.mk + +CMAKE_ARGS += -DCMAKE_SYSTEM_PROCESSOR=x86_64 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/qnx.nto.toolchain.cmake b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/qnx.nto.toolchain.cmake new file mode 100644 index 00000000000..f87ed721870 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/build_qnx/qnx.nto.toolchain.cmake @@ -0,0 +1,43 @@ +if("$ENV{QNX_HOST}" STREQUAL "") + message(FATAL_ERROR "QNX_HOST environment variable not found. Please set the variable to your host's build tools") +endif() +if("$ENV{QNX_TARGET}" STREQUAL "") + message(FATAL_ERROR "QNX_TARGET environment variable not found. Please set the variable to the qnx target location") +endif() + +if(CMAKE_HOST_WIN32) + set(HOST_EXECUTABLE_SUFFIX ".exe") + #convert windows paths to cmake paths + file(TO_CMAKE_PATH "$ENV{QNX_HOST}" QNX_HOST) + file(TO_CMAKE_PATH "$ENV{QNX_TARGET}" QNX_TARGET) +else() + set(QNX_HOST "$ENV{QNX_HOST}") + set(QNX_TARGET "$ENV{QNX_TARGET}") +endif() + +message(STATUS "using QNX_HOST ${QNX_HOST}") +message(STATUS "using QNX_TARGET ${QNX_TARGET}") + +set(CMAKE_SYSTEM_NAME QNX) +set(CMAKE_C_COMPILER ${QNX_HOST}/usr/bin/qcc) +set(CMAKE_CXX_COMPILER ${QNX_HOST}/usr/bin/qcc) +set(CMAKE_AR "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ar${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "archiver") +set(CMAKE_RANLIB "${QNX_HOST}/usr/bin/nto${CMAKE_SYSTEM_PROCESSOR}-ranlib${HOST_EXECUTABLE_SUFFIX}" CACHE PATH "ranlib") + +if ("${GCC_VER}" STREQUAL "") + set(GCC_VERSION "" CACHE STRING "gcc_ver") +else() + set(GCC_VERSION "${GCC_VER}," CACHE STRING "gcc_ver") +endif() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -V${GCC_VERSION}gcc_nto${CMAKE_SYSTEM_PROCESSOR} ${EXTRA_CMAKE_C_FLAGS}" CACHE STRING "c_flags") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -V${GCC_VERSION}gcc_nto${CMAKE_SYSTEM_PROCESSOR} ${EXTRA_CMAKE_CXX_FLAGS}" CACHE STRING "cxx_flags") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "exe_linker_flags") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EXTRA_CMAKE_LINKER_FLAGS}" CACHE STRING "so_linker_flags") + +set(CMAKE_FIND_ROOT_PATH ${VSOMEIP_EXTERNAL_DEPS_INSTALL};${VSOMEIP_EXTERNAL_DEPS_INSTALL}/${CPUVARDIR};${QNX_TARGET};${QNX_TARGET}/${CPUVARDIR}) + +set(CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries.") +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-security.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-security.json new file mode 100644 index 00000000000..aa3e0912e57 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-security.json @@ -0,0 +1,75 @@ +{ + "unicast" : "10.0.3.1", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1344" + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : "0x1277", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : "0x1344", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-client.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-client.json new file mode 100644 index 00000000000..28e1a0c45b4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-client.json @@ -0,0 +1,84 @@ +{ + "unicast" : "192.168.56.101", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "second-client-sample", + "id" : "0x1344" + }, + { + "name" : "third-client-sample", + "id" : "0x1345" + }, + { + "name" : "fourth-client-sample", + "id" : "0x1346" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "192.168.56.102", + "reliable" : { "port" : "30509", "magic-cookies" : false }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true" + }, + { + "event" : "0x0778", + "is_field" : "false" + }, + { + "event" : "0x0779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ] + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-service.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-service.json new file mode 100644 index 00000000000..e3f0e81df82 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tcp-service.json @@ -0,0 +1,75 @@ +{ + "unicast" : "192.168.56.102", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : { "port" : "30509", "magic-cookies" : "false" }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "false", + "is_reliable" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x0778", + "is_field" : "true", + "is_reliable" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x0779", + "is_field" : "false", + "is_reliable" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ] + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tracing.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tracing.json new file mode 100644 index 00000000000..e8497a6e01c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local-tracing.json @@ -0,0 +1,86 @@ +{ + "unicast" : "10.0.2.15", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "tracing" : + { + "enable" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1344" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x0778", + "is_field" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x0779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ], + "is_multicast" : "true" + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local.json new file mode 100644 index 00000000000..6edc8c02d79 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-local.json @@ -0,0 +1,82 @@ +{ + "unicast" : "10.0.2.15", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1344" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x0778", + "is_field" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x0779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ], + "is_multicast" : "true" + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client-security.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client-security.json new file mode 100644 index 00000000000..a9701346c94 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client-security.json @@ -0,0 +1,74 @@ +{ + "unicast" : "10.0.3.28", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "second-client-sample", + "id" : "0x1344" + }, + { + "name" : "third-client-sample", + "id" : "0x1345" + }, + { + "name" : "fourth-client-sample", + "id" : "0x1346" + } + ], + "clients" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : [ "41234" ] + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "credentials" : { "uid" : "0", "gid" : "0" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client.json new file mode 100644 index 00000000000..0431468af4e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-client.json @@ -0,0 +1,53 @@ +{ + "unicast" : "192.168.56.101", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "second-client-sample", + "id" : "0x1344" + }, + { + "name" : "third-client-sample", + "id" : "0x1345" + }, + { + "name" : "fourth-client-sample", + "id" : "0x1346" + } + ], + "clients" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : [ "41234" ] + } + ], + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service-security.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service-security.json new file mode 100644 index 00000000000..979bbf04caf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service-security.json @@ -0,0 +1,88 @@ +{ + "unicast" : "10.0.3.1", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" } + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.234", + "port" : "32344" + } + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : "0x1277", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service.json new file mode 100644 index 00000000000..f3bf474185b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-tcp-service.json @@ -0,0 +1,85 @@ +{ + "unicast" : "192.168.56.101", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" }, + "events" : + [ + { + "event" : "0x8777", + "is_field" : "false", + "is_reliable" : "true", + "update-cycle" : "2000" + }, + { + "event" : "0x8778", + "is_field" : "true", + "is_reliable" : "true", + "update-cycle" : "0" + }, + { + "event" : "0x8779", + "is_field" : "false", + "is_reliable" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x8777", "0x8778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x8778", "0x8779" ] + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x8777", "0x8779" ] + } + ] + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.234", + "port" : "32344" + } + } + ], + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client-security.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client-security.json new file mode 100644 index 00000000000..020c9a0e8aa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client-security.json @@ -0,0 +1,74 @@ +{ + "unicast" : "10.0.3.28", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "second-client-sample", + "id" : "0x1344" + }, + { + "name" : "third-client-sample", + "id" : "0x1345" + }, + { + "name" : "fourth-client-sample", + "id" : "0x1346" + } + ], + "clients" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : [ 40000, 40002 ] + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "credentials" : { "uid" : "0", "gid" : "0" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client.json new file mode 100644 index 00000000000..0f3bcf0fd19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-client.json @@ -0,0 +1,53 @@ +{ + "unicast" : "192.168.56.101", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "second-client-sample", + "id" : "0x1344" + }, + { + "name" : "third-client-sample", + "id" : "0x1345" + }, + { + "name" : "fourth-client-sample", + "id" : "0x1346" + } + ], + "clients" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : [ 40000, 40002 ] + } + ], + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service-security.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service-security.json new file mode 100644 index 00000000000..be86b94606a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service-security.json @@ -0,0 +1,88 @@ +{ + "unicast" : "10.0.3.1", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509" + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.234", + "port" : "32344" + } + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "client" : "0x1277", + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + } + ] + } + }, + { + "client" : { "first" : "0x1343", "last" : "0x1346" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service.json new file mode 100644 index 00000000000..728dd75d491 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip-udp-service.json @@ -0,0 +1,88 @@ +{ + "unicast" : "192.168.56.101", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "events" : + [ + { + "event" : "0x8777", + "is_field" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x8778", + "is_field" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x8779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x8777", "0x8778" ] + + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x8778", "0x8779" ], + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + } + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x8777", "0x8779" ] + } + ] + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.234", + "port" : "32344" + } + } + ], + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip.json b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip.json new file mode 100644 index 00000000000..53b977df45f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/config/vsomeip.json @@ -0,0 +1,55 @@ +{ + "unicast" : "192.168.56.101", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" }, + "dlt" : "false" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + }, + { + "name" : "other-client-sample", + "id" : "0x1344" + }, + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" }, + "unreliable" : "31000" + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "reliable" : { "port" : "30506", "enable-magic-cookies" : false }, + "unreliable" : "31000" + } + ], + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/.gitignore b/lib/libsomeip-c/vsomeip-3.5.1/documentation/.gitignore new file mode 100644 index 00000000000..1e9a582d879 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/.gitignore @@ -0,0 +1,2 @@ +*.qea +asciidoctor diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/offer_service.drawio.svg b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/offer_service.drawio.svg new file mode 100644 index 00000000000..716d0cc32ce --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/offer_service.drawio.svg @@ -0,0 +1,142 @@ +<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="561px" height="291px" viewBox="-0.5 -0.5 561 291" content="<mxfile><diagram id="1f2M6tHVN4a4N1YMWaA0" name="Page-1">5ZdNc5swEIZ/DdcOICDxsXbS9NJppz7krKI1aCokRghj99d3MeJTZJJ23GYyOVl6tbvSPotY7JFdcXrQtMy/KAbCC3128sidF4ZBFEf40ypnq/iEdEqmObPaKOz5L+gNrVpzBtXM0CglDC/nYqqkhNTMNKq1auZmByXmu5Y0A0fYp1S46iNnJu/U29gf9c/As7zfOfDtSkF7YytUOWWqmUjk3iM7rZTpRsVpB6Kl13Pp/D49sTocTIM0L3EIN53HkYraJmcPZs59tlrVkkHr4Htk2+TcwL6kabvaYIFRy00hcBbgsDJa/YSdEkqjIpVEs617KnvQI2gDp4lkT/kAqgCjz2hiVyMLrH9k+nkz8o8Tq+UT9uHGitTWPBtCj1hwYMmsUyIOpK+HA+gWE+gjRxRLZuiPDyM8z+sKaG4XaBIXzYBriubmCmQih8x3oOzCghqeemEicLftD2SVZO0Ir+SBZ7XGVSXbdwA19FXpRWH8eviSp/Cxs6TFm+QXxv+R343D71Fjwm8aIFl5tf0zgMR3CHKZipqtvNIk+9j2TpypEiQmj4rtzQHmt2W0yi9tIlhjBMzpqQtoLqEpgf5aahBYuuM81hoCG+6b4rjLQNtpJJvoQzwPUqlap2D9pr1zESrynw1lqM7AOKEuVRnyfFmhgndeqOGT6Y/LFCwCLe/NFYsUvrcikQXb+G+LtLhLJLlWkXA6fk535uO/EnL/Gw==</diagram></mxfile>"> + <defs/> + <g> + <rect x="0" y="0" width="560" height="290" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/> + <ellipse cx="110" cy="55" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 55px; margin-left: 41px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Offer service + </div> + </div> + </div> + </foreignObject> + <text x="110" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Offer service + </text> + </switch> + </g> + <ellipse cx="455" cy="55" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 55px; margin-left: 386px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Read static + <br/> + configuration data + </div> + </div> + </div> + </foreignObject> + <text x="455" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Read static... + </text> + </switch> + </g> + <ellipse cx="455" cy="145" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 145px; margin-left: 386px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Read dynamic + <br/> + configuration data + </div> + </div> + </div> + </foreignObject> + <text x="455" y="149" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Read dynamic... + </text> + </switch> + </g> + <ellipse cx="455" cy="235" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 235px; margin-left: 386px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Write dynamic + <br/> + configuration data + </div> + </div> + </div> + </foreignObject> + <text x="455" y="239" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Write dynamic... + </text> + </switch> + </g> + <path d="M 200 54.5 L 357.76 54.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/> + <path d="M 345.88 61 L 358.88 54.5 L 345.88 48" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 55px; margin-left: 280px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"> + include + </div> + </div> + </div> + </foreignObject> + <text x="280" y="58" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle"> + include + </text> + </switch> + </g> + <path d="M 200 80 L 367.85 129.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/> + <path d="M 354.62 132.25 L 368.93 129.68 L 358.29 119.78" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 105px; margin-left: 285px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"> + include + </div> + </div> + </div> + </foreignObject> + <text x="285" y="108" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle"> + include + </text> + </switch> + </g> + <path d="M 190 110 L 358.12 218.79" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/> + <path d="M 344.62 217.79 L 359.06 219.39 L 351.68 206.87" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 165px; margin-left: 275px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"> + include + </div> + </div> + </div> + </foreignObject> + <text x="275" y="168" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle"> + include + </text> + </switch> + </g> + </g> + <switch> + <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/> + <a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"> + <text text-anchor="middle" font-size="10px" x="50%" y="100%"> + Text is not SVG - cannot display + </text> + </a> + </switch> +</svg> \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml new file mode 100644 index 00000000000..d6e29dabff8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml @@ -0,0 +1,17 @@ +@startuml +actor "User application " as User +participant application +participant routing_manager +participant endpoint_manager +participant configuration + +User -> application : offer_service(service_t, instance_t, major_version_t, minor_version_t): bool +application -> routing_manager : offer_service(client_t, service_t, instance_t, major_version_t, minor_version_t):bool +routing_manager -> endpoint_manager : find_or_create_server_endpoint(service_t, instance_t): bool +endpoint_manager -> endpoint_manager : find_server_endpoint(service_t, instance_t) + +endpoint_manager --> routing_manager +routing_manager --> application +application --> User + +@enduml diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml.svg b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml.svg new file mode 100644 index 00000000000..52859f1446b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/sequence_offer_service.puml.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="369px" preserveAspectRatio="none" style="width:1738px;height:369px;background:#FFFFFF;" version="1.1" viewBox="0 0 1738 369" width="1738px" zoomAndPan="magnify"><defs/><g><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="65" x2="65" y1="84.0679" y2="285.892"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="528.5" x2="528.5" y1="84.0679" y2="285.892"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="1038.5" x2="1038.5" y1="84.0679" y2="285.892"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="1412" x2="1412" y1="84.0679" y2="285.892"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="1679.5" x2="1679.5" y1="84.0679" y2="285.892"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="110" x="5" y="79.9659">User application</text><ellipse cx="65" cy="13.5" fill="#E2E2F0" rx="8" ry="8" style="stroke:#181818;stroke-width:0.5;"/><path d="M65,21.5 L65,48.5 M52,29.5 L78,29.5 M65,48.5 L52,63.5 M65,48.5 L78,63.5 " fill="none" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="110" x="5" y="299.8579">User application</text><ellipse cx="65" cy="312.4599" fill="#E2E2F0" rx="8" ry="8" style="stroke:#181818;stroke-width:0.5;"/><path d="M65,320.4599 L65,347.4599 M52,328.4599 L78,328.4599 M65,347.4599 L52,362.4599 M65,347.4599 L78,362.4599 " fill="none" style="stroke:#181818;stroke-width:0.5;"/><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="89" x="484.5" y="50"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="75" x="491.5" y="71.9659">application</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="89" x="484.5" y="284.892"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="75" x="491.5" y="306.8579">application</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="131" x="973.5" y="50"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="117" x="980.5" y="71.9659">routing_manager</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="131" x="973.5" y="284.892"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="117" x="980.5" y="306.8579">routing_manager</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="142" x="1341" y="50"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="128" x="1348" y="71.9659">endpoint_manager</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="142" x="1341" y="284.892"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="128" x="1348" y="306.8579">endpoint_manager</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="105" x="1627.5" y="50"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="91" x="1634.5" y="71.9659">configuration</text><rect fill="#E2E2F0" height="33.0679" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="105" x="1627.5" y="284.892"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="91" x="1634.5" y="306.8579">configuration</text><polygon fill="#181818" points="517,113.7739,527,117.7739,517,121.7739,521,117.7739" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="65" x2="523" y1="117.7739" y2="117.7739"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="440" x="72" y="111.9649">offer_service(service_t, instance_t, major_version_t, minor_version_t): bool</text><polygon fill="#181818" points="1027,145.4799,1037,149.4799,1027,153.4799,1031,149.4799" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="529" x2="1033" y1="149.4799" y2="149.4799"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="486" x="536" y="143.6709">offer_service(client_t, service_t, instance_t, major_version_t, minor_version_t):bool</text><polygon fill="#181818" points="1400,177.186,1410,181.186,1400,185.186,1404,181.186" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="1039" x2="1406" y1="181.186" y2="181.186"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="349" x="1046" y="175.377">find_or_create_server_endpoint(service_t, instance_t): bool</text><line style="stroke:#181818;stroke-width:1.0;" x1="1412" x2="1454" y1="212.892" y2="212.892"/><line style="stroke:#181818;stroke-width:1.0;" x1="1454" x2="1454" y1="212.892" y2="225.892"/><line style="stroke:#181818;stroke-width:1.0;" x1="1413" x2="1454" y1="225.892" y2="225.892"/><polygon fill="#181818" points="1423,221.892,1413,225.892,1423,229.892,1419,225.892" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="254" x="1419" y="207.083">find_server_endpoint(service_t, instance_t)</text><polygon fill="#181818" points="1050,235.892,1040,239.892,1050,243.892,1046,239.892" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="1044" x2="1411" y1="239.892" y2="239.892"/><polygon fill="#181818" points="540,249.892,530,253.892,540,257.892,536,253.892" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="534" x2="1038" y1="253.892" y2="253.892"/><polygon fill="#181818" points="76,263.892,66,267.892,76,271.892,72,267.892" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="70" x2="528" y1="267.892" y2="267.892"/><!--SRC=[dP5B3e9038Rtd6BYIXEz00jluNfIXu7KG3ifXVDRG19UCSRLJFhulxyj16LnfqSRnK5ADGPGP78d1wqReba2KGoOW7HPiOeBTufK-GO8garFf28naXuc0rE9LIUJP3RQkDrNJdB7PHd5Mwh74C-Vr-lL8RKADFqRUB7uFafhJMC0QHcuvEx9N6TBQIDjdEzeeSPetatlR-w8tN8ClLsCiKkambjta0WQHnFcPIuy7dqUR2Vt1V6RS7QWkL_PVhJr0TSRjznmv3S0]--></g></svg> \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.drawio.svg b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.drawio.svg new file mode 100644 index 00000000000..ba6bbcce713 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.drawio.svg @@ -0,0 +1,266 @@ +<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="701px" height="471px" viewBox="-0.5 -0.5 701 471" content="<mxfile><diagram id="1f2M6tHVN4a4N1YMWaA0" name="Page-1">1Zpdk5owFIZ/jbcdIIB66bq77UU73Vm70/YSIUKmgdAQ/Oivb6IJX9GtYyXojZJDAjlvnhw5B0dgnm4/0iBPvpAI4pFjRdsReBw5ju16Lv8Slp20WAAcLDFFkbTVhgX6A1VHaS1RBItWR0YIZihvG0OSZTBkLVtAKdm0u60Ibt81D2KoGRZhgHXrdxSx5GCdeFZt/wRRnKg725Y8kwaqszQUSRCRTcMEnkZgTglhh6N0O4dYqKd0OYx7PnG2mhiFGTtngDM9jFgHuJTOyYmxnfKWkjKLoBhgjcDDJkEMLvIgFGc3fIG5LWEp5i2bHxaMkl9wTjCh3JKRjHd7kPeAlMHtyYnalfscHEhSyOiOd5EDxt5hhEJGab2p9R8rlZOG9u5YGgO55nF16VoWfiCVOaGSJtIszzEKA4ZIpunF1zQXh2WKZyETOjwI13l3/DlYQvxCCrQfCB6XhDGSNjrMMIrFCUY6up7Q64iqJyV01faRGjoTXUNwREL/Cgp6mkow4ltKNiUmDXfhFrEfjeOfgr4Pnmw9biWM+8ZONbJoJjZ3fUFueUZiTvvzJyUsSElDOS0ZiMTs3tWUQsxXf90OCMcUkkNfCOJ3rdYCTE6shboEC2gMmRzV0bmaxlnSAw3er6sVpMJvSNeIO64tDcY8ksJ/b/YrQNnRwfZ1Jm33CJTX2Nb2+F6odIehEli9UelqVC5EzBM/5PyDSEKD26TUOfLr0x+lk3uh1B+IUtAbpb5G6Uu5xKhIhJtrrkXMH47yW0ITuCbRnN4LmuOB0Ow+O10PzfG7ATSvML3REOoCg5xW2dZ/cdo/pRNDlE47lHY1vh6lE51Srsvehd8lLNigSNpuO6n0jsVOuy8mbd33s5is46UhKqdmqHStDpX9pUR60aOisshJVgwbKR3/DCwtrycs9frPjWKpNmbvXIL2cvTIpXKpAeY3iuJ4nwvtnzcHBRNMzgGzr3gJ7gZM2xCYvrGAqVxqgPmWRwHjgdJaIYijQbl0p0Ny6V7KpWEqHUNUjo2lQMqlBpWvMIRi7o6VwqIQr3GGBNO3hgTz0rpRC0wTybltqOjumiu623rV/VVlPDeRjvtOWwujhXfn0sK7eTQNVd67aAK7PzT10vsrxDAQWc9Nomm02q5KvneApjcQmv2V25VLzcS8XBYhRUuoMqDhK+5dPo2W3C9+k26eT0OvgzQ+vf741N8HvWXF7RPaZ7GdN+u/Kx00rf/1BZ7+Ag==</diagram></mxfile>"> + <defs/> + <g> + <rect x="0" y="0" width="700" height="470" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/> + <ellipse cx="350" cy="137.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <path d="M 350 145 L 350 170 M 350 150 L 335 150 M 350 150 L 365 150 M 350 170 L 335 190 M 350 170 L 365 190" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 197px; margin-left: 350px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> + Application + </div> + </div> + </div> + </foreignObject> + <text x="350" y="209" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Appli... + </text> + </switch> + </g> + <path d="M 145 45 L 305 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="75" cy="45" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 45px; margin-left: 6px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Offer service + </div> + </div> + </div> + </foreignObject> + <text x="75" y="49" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Offer service + </text> + </switch> + </g> + <path d="M 145 135 L 305 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="75" cy="135" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 135px; margin-left: 6px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Stop to offer a service + </div> + </div> + </div> + </foreignObject> + <text x="75" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Stop to offer a service + </text> + </switch> + </g> + <path d="M 145 225 L 305 180" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="75" cy="225" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 225px; margin-left: 6px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Publish eventgroup + </div> + </div> + </div> + </foreignObject> + <text x="75" y="229" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Publish eventgroup + </text> + </switch> + </g> + <path d="M 145 315 L 305 210" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="75" cy="315" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 315px; margin-left: 6px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Stop to publish a service + </div> + </div> + </div> + </foreignObject> + <text x="75" y="319" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Stop to publish a servi... + </text> + </switch> + </g> + <path d="M 163.89 400.25 L 315 220" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="125" cy="425" rx="55" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 425px; margin-left: 71px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Send request + </div> + </div> + </div> + </foreignObject> + <text x="125" y="429" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Send request + </text> + </switch> + </g> + <path d="M 242.5 390 L 325 230" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="242.5" cy="425" rx="52.5" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 103px; height: 1px; padding-top: 425px; margin-left: 191px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Send response + </div> + </div> + </div> + </foreignObject> + <text x="243" y="429" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Send response + </text> + </switch> + </g> + <path d="M 360 390 L 360 230" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="360" cy="425" rx="50" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 425px; margin-left: 311px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Trigger event + </div> + </div> + </div> + </foreignObject> + <text x="360" y="429" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Trigger event + </text> + </switch> + </g> + <path d="M 470 390 L 385 230" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="470" cy="425" rx="50" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 425px; margin-left: 421px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Update field + </div> + </div> + </div> + </foreignObject> + <text x="470" y="429" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Update field + </text> + </switch> + </g> + <path d="M 544.64 400.25 L 395 210" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="580" cy="425" rx="50" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 425px; margin-left: 531px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Receive message + </div> + </div> + </div> + </foreignObject> + <text x="580" y="429" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Receive message + </text> + </switch> + </g> + <path d="M 545 45 L 405 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="615" cy="45" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 45px; margin-left: 546px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Request service + </div> + </div> + </div> + </foreignObject> + <text x="615" y="49" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Request service + </text> + </switch> + </g> + <path d="M 545 135 L 405 160" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="615" cy="135" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 135px; margin-left: 546px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Release service + </div> + </div> + </div> + </foreignObject> + <text x="615" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Release service + </text> + </switch> + </g> + <path d="M 545 225 L 405 180" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="615" cy="225" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 225px; margin-left: 546px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Subscribe eventgroup + </div> + </div> + </div> + </foreignObject> + <text x="615" y="229" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Subscribe eventgroup + </text> + </switch> + </g> + <path d="M 545 315 L 405 200" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <ellipse cx="615" cy="315" rx="70" ry="35" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <g transform="translate(-0.5 -0.5)"> + <switch> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 315px; margin-left: 546px;"> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> + Unsubscribe eventgroup + </div> + </div> + </div> + </foreignObject> + <text x="615" y="319" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> + Unsubscribe eventgroup + </text> + </switch> + </g> + </g> + <switch> + <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/> + <a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"> + <text text-anchor="middle" font-size="10px" x="50%" y="100%"> + Text is not SVG - cannot display + </text> + </a> + </switch> +</svg> \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.puml b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.puml new file mode 100644 index 00000000000..1e432f36c1c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/diagrams/usecases_overview.puml @@ -0,0 +1,20 @@ +@startuml + +left to right direction +:Application: as User + +(Offer service) <-- User +(Stop to offer a service) <-- User +(Publish eventgroup) <-- User +(Stop to publish a service) <-- User +User -> (Send request) +User -> (Send response) +User -> (Trigger event) +User -> (Update field) +User -> (Receiv message) +User --> (Request service) +User --> (Release service) +User --> (Subscribe eventgroup) +User --> (Unsubscribe service) + +@enduml diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/doxygen.in b/lib/libsomeip-c/vsomeip-3.5.1/documentation/doxygen.in new file mode 100644 index 00000000000..9090b7382b0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/doxygen.in @@ -0,0 +1,1814 @@ +# Doxyfile 1.7.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "@PROJECT_NAME@-@PACKAGE_VERSION@" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/@DOCDIR@ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @PROJECT_SOURCE_DIR@/implementation \ + @PROJECT_SOURCE_DIR@/interface + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = @GENERATE_HTML@ + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = @GENERATE_HTMLHELP@ + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = ../@PROJECT@.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = @HHC_PATH@ + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = @GENERATE_CHI@ + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = @GENERATE_LATEX@ + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = YES + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = @PAPER_SIZE@ + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = @GENERATE_PDF@ + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = @GENERATE_RTF@ + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = YES + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = @GENERATE_MAN@ + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = @GENERATE_XML@ + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = @DOCDIR@/@PROJECT@.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = @HAVE_DOT@ + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/network-tests.md b/lib/libsomeip-c/vsomeip-3.5.1/documentation/network-tests.md new file mode 100644 index 00000000000..e40ed7b434c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/network-tests.md @@ -0,0 +1,69 @@ +# vSomeIP - Run Network-Tests locally + +The network-tests can be run on your laptop using the Docker Compose setup designed for Zuul. +This page will guide you to accomplish that goal. + + +## Prerequisites + +1. Up-to-date clone of vsomeip, checked out on maintain/3.5 or on a branch recently created from it. +2. Recent Docker version with Compose plugin installed + + a. Check Docker version with docker info, must be at least 23.x.y or 24.x.y, otherwise follow the official instructions to install a newer version: https://docs.docker.com/engine/install/ubuntu/ + + $ docker info + Client: Docker Engine - Community + Version: 24.0.2 + (...) + b. Check if the Docker Compose plugin is installed with docker compose version. If the command fails, follow the official instructions to rectify your Docker installation: https://docs.docker.com/engine/install/ubuntu/ + + $ docker compose version + Docker Compose version v2.18.1 + +## Main steps + +1. Clone dlt-daemon to the same Project folder as vsomeip. + + git clone https://github.com/COVESA/dlt-daemon.git + + $ ls + dlt-daemon vsomeip + +2. Set the sanitizer type you'd like to use (use LEAK if you don't know or care which one gets used) + + export SANITIZER_TYPE=<ADDRESS | LEAK | THREAD | UNDEFINED> + + Example: + + export SANITIZER_TYPE=LEAK + + +3. Create the containers (you must be inside the vsomeip repo to run this step). This will first build the Docker image used by both that contains everything needed to build and run the network-tests (CMake, GCC, Boost, etc.) + + docker compose --project-directory zuul/network-tests build + +4. Start the containers (same as above, you must be inside the repo directory). This will build vsomeip-lib and then run the network-tests + + docker compose --project-directory zuul/network-tests up + + +## FAQ + +**Question**: I get a strange CMake error when I start the containers + + This occurs if you have recently rebuilt vsomeip-lib outside the Docker Compose setup. + It can also occur when rebuilding vsomeip-lib after pulling new changes from upstream. + + You can fix it by removing the build directory located inside the repo directory. + + +**Question**: I'd like to run only a subset of the network-tests + + Locate the CMakePresets.json file and add a "filter" entry inside the preset named ci-network-tests below "execution", like so: + + "filter": { + "include": { + "name": "<regex filter>" + } +} + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/readme.md b/lib/libsomeip-c/vsomeip-3.5.1/documentation/readme.md new file mode 100644 index 00000000000..ad42f898988 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/readme.md @@ -0,0 +1,26 @@ +# Multicast +To use IP multicast, the route must be added. In Linux this can be done +by: + +``` +# route add -net 224.0.0.0/4 dev eth0 +``` + +Other OSes may have different ways to do this. + +# Diagrams +## Use cases Overview + +![Use cases Overview](./diagrams/usecases_overview.drawio.svg) + +## Use case Offer service + +![Offer service](./diagrams/offer_service.drawio.svg) + +## Sequence Offer service + +![Seq Offer service](./diagrams/sequence_offer_service.puml.svg) + +# Support and review +## Open and closed points +- [ ] update the EA model to match the current implementation diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeip.eap b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeip.eap new file mode 100755 index 00000000000..dfe4c2665c0 Binary files /dev/null and b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeip.eap differ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipProtocol.md b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipProtocol.md new file mode 100644 index 00000000000..e3a89696188 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipProtocol.md @@ -0,0 +1,385 @@ +# vSomeIP command documentation + +## VSOMEIP_ASSIGN_CLIENT (0x00) + + Command 00 + Version xx xx + Client xx xx + Size xx xx xx xx + Name xx ... xx ;#xx = Size + +## VSOMEIP_ASSIGN_CLIENT_ACK (0x01) + + Command 01 + Version xx xx + Client xx xx + Size 02 00 00 00 + Assigned xx xx + +## VSOMEIP_REGISTER_APPLICATION (0x02) + + Command 02 + Version xx xx + Client xx xx + Size 00 00 00 00 + +## VSOMEIP_DEREGISTER_APPLICATION (0x03) + + Command 03 + Version xx xx + Client xx xx + Size 00 00 00 00 + + +## VSOMEIP_APPLICATION_LOST (0x04) + +`<unused>` + + +## VSOMEIP_ROUTING_INFO (0x05) + + Command 05 + Version xx xx + Client xx xx + Size xx xx xx xx + Entries + SubCommand xx ; RIE_ADD_CLIENT (0x0) or RIE_DEL_CLIENT (0x1) + Size xx xx xx xx + Client xx xx + [Address] xx .. xx ; Size - sizeof(Client) - sizeof(Port) + [Port] xx + + SubCommand xx ; RIE_ADD_SERVICE_INSTANCE (0x2) or RIE_DEL_SERVICE_INSTANCE (0x3) + Size xx xx xx xx ; Command size + Size xx xx xx xx ; Client info size + Client xx xx + [Address] xx .. xx ; Client info size - sizeof(Client) - sizeof(Port) + [Port] xx + Size xx xx xx xx ; Services size + Service xx xx + Instance xx xx + Major xx + Minor xx xx xx xx + + +## VSOMEIP_REGISTERED_ACK (0x06) + + Command 06 + Version xx xx + Client xx xx + Size 00 00 00 00 + + +## VSOMEIP_PING (0x07) + + Command 07 + Version xx xx + Client 00 00 + Size 00 00 00 00 + + +## VSOMEIP_PONG (0x08) + + Command 08 + Version xx xx + Client xx xx + Size 00 00 00 00 + + +## VSOMEIP_OFFER_SERVICE (0x10) + + Command 10 + Version xx xx + Client xx xx + Size 09 00 00 00 + Service xx xx + Instance xx xx + Major xx + Minor xx xx xx xx + + +## VSOMEIP_STOP_OFFER_SERVICE (0x11) + + Command 11 + Version xx xx + Client xx xx + Size 09 00 00 00 + Service xx xx + Instance xx xx + Major xx + Minor xx xx xx xx + + +## VSOMEIP_SUBSCRIBE (0x12) + + Command 12 + Version xx xx + Client xx xx + Size xx xx xx xx + Service xx xx + Instance xx xx + Eventgroup xx xx + Major xx + Event xx xx + Pending ID xx xx + Filter + OnChange xx + OnChangeResetsInterval xx + Interval xx xx xx xx xx xx xx xx + Ignore (per entry) + Key xx xx xx xx xx xx xx xx + Value xx + + +## VSOMEIP_UNSUBSCRIBE (0x13) + +## VSOMEIP_EXPIRE (0x2A) + + Command 13/2A + Version xx xx + Client xx xx + Size 0a 00 00 00 + Service xx xx + Instance xx xx + Eventgroup xx xx + Event xx xx + Pending ID xx xx + + +## VSOMEIP_REQUEST_SERVICE (0x14) + + Command 14 + Version xx xx + Client xx xx + Size xx xx xx xx + Entries + Service xx xx + Instance xx xx + Major xx + Minor xx xx xx xx + + +## VSOMEIP_RELEASE_SERVICE (0x15) + + Command 15 + Version xx xx + Client xx xx + Size 04 00 00 00 + Service xx xx + Instance xx xx + + +## VSOMEIP_SUBSCRIBE_NACK (0x16) + + Command 16 + Version xx xx + Client xx xx + Size 0c 00 00 00 + Service xx xx + Instance xx xx + Eventgroup xx xx + Subscriber xx xx + Event xx xx + ID xx xx + + +## VSOMEIP_SUBSCRIBE_ACK (0x17) + + Command 17 + Version xx xx + Client xx xx + Size 0c 00 00 00 + Service xx xx + Instance xx xx + Eventgroup xx xx + Subscriber xx xx + Event xx xx + ID xx xx + + +## VSOMEIP_SEND (0x18) + +## VSOMEIP_NOTIFY (0x19) + +## VSOMEIP_NOTIFY_ONE (0x1A) + + Command 18|19|1a + Version xx xx + Client xx xx + Size xx xx xx xx + Instance xx xx + Reliable xx ; UDP (00) or TCP (01) + Status xx ; CRC of E2E - protected messages + Destination xx xx ; Client ID of the receiver + Payload xx ... xx + + +## VSOMEIP_REGISTER_EVENT (0x1B) + + Command 1b + Version xx xx + Client xx xx + Size xx xx xx xx ; 10 + #eventgroups * 2 + Entries + Service xx xx + Instance xx xx + Notifier xx xx + Type xx ; ET_EVENT (00), ET_SELECTIVE_EVENT(01) or ET_FIELD(02) + Provided xx ; False (00) or True (01) + Reliability xx ; UDP (00) or TCP (01) + IsCyclic xx + Num Eventgroups xx xx + Entries + Eventgroup xx xx + + +## VSOMEIP_UNREGISTER_EVENT (0x1C) + + Command 1c + Version xx xx + Client xx xx + Size 07 00 00 00 + Service xx xx + Instance xx xx + Notifier xx xx + Provided xx + + +## VSOMEIP_ID_RESPONSE (0x1D) + +`<unused>` + + +## VSOMEIP_ID_REQUEST (0x1E) + +`<unused>` + + +## VSOMEIP_OFFERED_SERVICES_REQUEST (0x1F) + + Command 1f + Version xx xx + Client xx xx + Size 01 00 00 00 + OfferType xx (00 = LOCAL, 01 = REMOTE, 02 = ALL) + + +## VSOMEIP_OFFERED_SERVICES_RESPONSE (0x20) + + Command 20 + Version xx xx + Client xx xx + Size xx xx xx xx + OfferedServices + Subcommand xx (00 = ADD CLIENT, 01 = ADD SERVICE INSTANCE, 02 = DELETE SERVICE INSTANCE, 03 = DELETE CLIENT) + Size xx xx xx xx + ServiceInstances + Service xx xx + Instance xx xx + Major xx xx + Minor xx xx + + +## VSOMEIP_UNSUBSCRIBE_ACK (0x21) + + Command 21 + Version xx xx + Client xx xx + Size 08 00 00 00 + Service xx xx + Instance xx xx + Eventgroup xx xx + Id xx xx + + +## VSOMEIP_RESEND_PROVIDED_EVENTS (0x22) + + Command 22 + Version xx xx + Client xx xx + Size 04 00 00 00 + PendingOfferId xx xx xx xx + + +## VSOMEIP_UPDATE_SECURITY_POLICY (0x23) + +## VSOMEIP_UPDATE_SECURITY_POLICY_INT (0x29) + + Command 23/29 + Version xx xx + Client xx xx + Size xx xx xx xx + UpdateId xx xx xx xx + Policy xx ... xx + + +## VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE (0x24) + + Command 24 + Version xx xx + Client xx xx + Size 04 00 00 00 + UpdateId xx xx xx xx + + +## VSOMEIP_REMOVE_SECURITY_POLICY (0x25) + + Command 25 + Version xx xx + Client xx xx + Size 0c 00 00 00 + UpdateId xx xx xx xx + Uid xx xx xx xx + Gid xx xx xx xx + + +## VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE (0x26) + + Command 26 + Version xx xx + Client xx xx + Size 04 00 00 00 + UpdateId xx xx xx xx + + +## VSOMEIP_UPDATE_SECURITY_CREDENTIALS (0x27) + + Command 27 + Version xx xx + Client xx xx + Size xx xx xx xx + Credentials + Uid xx xx xx xx + Gid xx xx xx xx + + +## VSOMEIP_DISTRIBUTE_SECURITY_POLICIES (0x28) + + Command 28 + Version xx xx + Client xx xx xx xx + Size xx xx xx xx + PoliciesCount xx xx xx xx + Policies + Size xx xx xx xx + Data xx ... xx + + +## VSOMEIP_SUSPEND (0x30) + + Command 30 + Version xx xx + Size xx xx xx xx + + +## VSOMEIP_CONFIG (0x31) + + Command 31 + Version 00 00 + Client xx xx + Size xx xx xx xx + Configurations + Key Size xx xx xx xx + Key (string) xx ... xx + Value Size xx xx xx xx + Value (string) xx ... xx diff --git a/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipUserGuide.md b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipUserGuide.md new file mode 100644 index 00000000000..e2a3cc0df51 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/documentation/vsomeipUserGuide.md @@ -0,0 +1,2314 @@ +# Legal notice + +## Copyright +Copyright (C) 2015-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + +## License + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +## Version + +This documentation was generated for version 3.5 of vSomeIP. + +# vSomeIP Overview + +The vSomeIP stack implements the http://some-ip.com/[Scalable service-Oriented +MiddlewarE over IP (SOME/IP)] protocol. The stack consists out of: + +* a shared library for SOME/IP (`libvsomeip.so`) +* a second shared library for SOME/IP's service discovery (`libvsomeip-sd.so`) + which is loaded during runtime if the service discovery is enabled. + +# Build Instructions + +## Dependencies + +* A C++17 enabled compiler is needed +* vSomeIP uses cmake as buildsystem. +* vSomeIP uses Boost >= 1.66: + * Ubuntu 22.04: + * `sudo apt-get install libboost-system1.74-dev libboost-thread1.74-dev libboost-log1.74-dev` +* For the tests Google's test framework + https://github.com/google/googletest/releases +* To build the documentation doxygen and graphviz are needed: + * `sudo apt-get install doxygen graphviz` + +## Compilation + +For compilation call: + +```bash +mkdir build +cd build +cmake .. +make +``` + +To specify a installation directory (like `--prefix=` if you're used to +autotools) call cmake like: + +```bash +cmake -DCMAKE_INSTALL_PREFIX:PATH=$YOUR_PATH .. +make +make install +``` + +### Compilation with predefined base path + +To predefine the base path, the path that is used to create the local sockets, +call cmake like: + +```bash +cmake -DBASE_PATH=<YOUR BASE PATH> .. +``` + +The default base path is /tmp. + +### Compilation with predefined unicast and/or diagnosis address + +To predefine the unicast address, call cmake like: + +```bash +cmake -DUNICAST_ADDRESS=<YOUR IP ADDRESS> .. +``` + +To predefine the diagnosis address, call cmake like: + +```bash +cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> .. +``` + +The diagnosis address is a single byte value. + +### Compilation with custom default configuration folder + +To change the default configuration folder, call cmake like: + +```bash +cmake -DDEFAULT_CONFIGURATION_FOLDER=<DEFAULT CONFIGURATION FOLDER> .. +``` + +The default configuration folder is /etc/vsomeip. + +### Compilation with custom default configuration file + +To change the default configuration file, call cmake like: + +```bash +cmake -DDEFAULT_CONFIGURATION_FILE=<DEFAULT CONFIGURATION FILE> .. +``` + +The default configuration file is /etc/vsomeip.json. + +### Compilation with changed (maximimum) wait times for local TCP ports + +If local communication is done via TCP, we depend on the availability +of the network. Therefore, server port creation and therefore port +assignment might fail. If the failure is causes by the port already +being in use, we use the next available port. For all other failure, +we wait for a wait time until we retry with the same port. If the +overall wait time of all retries exceeds the maximum wait time, +the endpoint creation is aborted. To configure wait time and maximum +wait time, call cmake with: + +```bash +cmake -DLOCAL_TCP_PORT_WAIT_TIME=50 -DLOCAL_TCP_PORT_MAX_WAIT_TIME=2000 .. +``` + +The default values are a wait time of 100ms and a maximum wait time of 10000ms. +These configurations have no effect if local communication uses UDS (default). + +### Compilation with signal handling + +To compile vsomeip with signal handling (SIGINT/SIGTERM) enabled, +call cmake like: + +```bash +cmake -DENABLE_SIGNAL_HANDLING=1 .. +``` + +In the default setting, the application has to take care of shutting +down vsomeip in case these signals are received. + +### Compilation with user defined "READY" message + +To compile vsomeip with a user defined message signal the IP routing +to be ready to send/receive messages, call cmake like: + +```bash +cmake -DROUTING_READY_MESSAGE=<YOUR MESSAGE> .. +``` + + +### Compilation with vSomeIP 2 compatibility layer + +To compile vsomeip with enabled vSomeIP 2 compatibility layer, call +cmake like: + +```bash +cmake -DENABLE_COMPAT=1 .. +``` + +### Compilation of examples + +For compilation of the examples call: + +```bash +mkdir build +cd build +cmake .. +make examples +``` + +### Compilation of tests + +To compile the tests, first unzip gtest to location of your desire. +Some of the tests require a second node on the same network. There are two cmake +variables which are used to automatically adapt the json files to the used +network setup: + +* `TEST_IP_MASTER`: The IP address of the interface which will act as test + master. +* `TEST_IP_SLAVE`: The IP address of the interface of the second node which will + act as test slave. + +If one of this variables isn't specified, only the tests using local +communication exclusively will be runnable. + +Additionally the unit tests require enabled signal handling which can be enabled +via the `ENABLE_SIGNAL_HANDLING` cmake variable. + +Example, compilation of tests: + +```bash +mkdir build +cd build +export GTEST_ROOT=$PATH_TO_GTEST/gtest-1.7.0/ +cmake -DENABLE_SIGNAL_HANDLING=1 -DTEST_IP_MASTER=10.0.3.1 -DTEST_IP_SLAVE=10.0.3.125 .. +make check +``` + +Additional make targets for the tests: + +* Call `make build_tests` to only compile the tests +* Call `ctest` in the build directory to execute the tests without a verbose + output +* To run single tests call `ctest --verbose --tests-regex $TESTNAME` short + form: `ctest -V -R $TESTNAME` +* To list all available tests run `ctest -N`. +* For further information about the tests please have a look at the + `readme.txt` in the `test` subdirectory. + +For development purposes two cmake variables exist which control if the +json files and test scripts are copied (default) or symlinked into the build +directory. These settings are ignored on Windows. + +* `TEST_SYMLINK_CONFIG_FILES`: Controls if the json and scripts needed + to run the tests are copied or symlinked into the build directory. (Default: + OFF, ignored on Windows) +* `TEST_SYMLINK_CONFIG_FILES_RELATIVE`: Controls if the json and scripts needed + to run the tests are symlinked relatively into the build directory. + (Default: OFF, ignored on Windows) + +Example cmake call: + +```bash +cmake -DTEST_SYMLINK_CONFIG_FILES=ON -DTEST_SYMLINK_CONFIG_FILES_RELATIVE=ON .. +``` + +For compilation of only a subset of tests (for a quick +functionality check) the cmake variable `TESTS_BAT` has +to be set: + +Example cmake call: +```bash +cmake -DTESTS_BAT=ON .. +``` + +### Compilation of vsomeip_ctrl + +For compilation of the [vsomeip_ctrl](#vsomeip_ctrl) utility call: + +```bash +mkdir build +cd build +cmake .. +make vsomeip_ctrl +``` + +### Generating the documentation + +To generate the documentation call cmake as described in [Compilation](#compilation) and +then call `make doc`. +This will generate: + +* The README file in html: `$BUILDDIR/documentation/README.html` +* A doxygen documentation in `$BUILDDIR/documentation/html/index.html` + +# Starting vsomeip Applications / Used environment variables + +On startup the following environment variables are read out: + +* `VSOMEIP_APPLICATION_NAME`: This environment variable is used to specify the + name of the application. This name is later used to map a client id to the + application in the configuration file. It is independent from the + application's binary name. +* `VSOMEIP_CONFIGURATION`: vsomeip uses the default configuration file `/etc/vsomeip.json` + and/or the default configuration folder `/etc/vsomeip`. This can be overridden by a + local configuration file `./vsomeip.json` and/or a local configuration folder `./vsomeip`. + If `VSOMEIP_CONFIGURATION` is set to a valid file or directory path, this is used instead + of the standard configuration (thus neither default nor local file/folder will be parsed). +* `VSOMEIP_CONFIGURATION_<application>`: Application-specific version of `VSOMEIP_CONFIGURATION`. + Please note that <application> must be valid as part of an environment variable. +* `VSOMEIP_MANDATORY_CONFIGURATION_FILES`: vsomeip allows to specify mandatory configuration + files to speed-up application startup. While mandatory configuration files are read by all + applications, all other configuration files are only read by the application that is + responsible for connections to external devices. If this configuration variable is not set, + the default mandatory files vsomeip_std.json, vsomeip_app.json and vsomeip_plc.json are used. +* `VSOMEIP_CLIENTSIDELOGGING`: Set this variable to an empty string to enable logging of + any received messages to DLT in all applications acting as routing manager proxies. For + example add the following line to the application's systemd service file: + `Environment=VSOMEIP_CLIENTSIDELOGGING=""` + To enable service-specific logs, provide a space- or colon-separated list of ServiceIDs (using + 4-digit hexadecimal notation, optionally followed by dot-separted InstanceID). For example: + `Environment=VSOMEIP_CLIENTSIDELOGGING="b003.0001 f013.000a 1001 1002"` + `Environment=VSOMEIP_CLIENTSIDELOGGING="b003.0001:f013.000a:1001:1002"` + +NOTE: If the file/folder that is configured by `VSOMEIP_CONFIGURATION` does _not_ exist, +the default configuration locations will be used. + +NOTE: vsomeip will parse and use the configuration from all files in a configuration folder +but will _not_ consider directories within the configuration folder. + +In the following example the application `my_vsomeip_application` is started. +The settings are read from the file `my_settings.json` in the current working +directory. The client id for the application can be found under the name +`my_vsomeip_client` in the configuration file. + +```bash +#!/bin/bash +export VSOMEIP_APPLICATION_NAME=my_vsomeip_client +export VSOMEIP_CONFIGURATION=my_settings.json +./my_vsomeip_application +``` + +# Configuration File Structure + +The configuration files for vsomeip are [JSON](http://www.json.org)-Files and are +composed out of multiple key value pairs and arrays. + +> * An object is an unordered set of name/value pairs. An object begins with `{ +> (left brace)` and ends with `} (right brace)`. Each name is followed by `: +> (colon)` and the name/value pairs are separated by `, (comma)`. +> +> * An array is an ordered collection of values. An array begins with `[ (left +> bracket)` and ends with `] (right bracket)`. Values are separated by `, +> (comma)`. +> +> * A value can be a _string_ in double quotes, or a _number_, or `true` or `false` +> or `null`, or an _object_ or an _array_. These structures can be nested. + +Configuration file element explanation: + +* 'unicast' + + The IP address of the host system. + +* 'netmask' + + The netmask to specify the subnet of the host system. + +* 'device' (optional) + + If specified, IP endpoints will be bound to this device. + +* 'diagnosis' + + The diagnosis address (byte) that will be used to build client identifiers. The + diagnosis address is assigned to the most significant byte in all client + identifiers if not specified otherwise (for example through a predefined client + ID). + +* 'diagnosis_mask' + + The diagnosis mask (2 byte) is used to control the maximum amount of allowed + concurrent vsomeip clients on an ECU and the start value of the client IDs. + + The default value is `0xFF00` meaning + the most significant byte of the client ID is reserved for the diagnosis + address and the client IDs will start with the diagnosis address as specified. + The maximum number of clients is 255 as the Hamming weight of the inverted mask + is 8 (2^8 = 256 - 1 (for the routing manager) = 255). The resulting client ID + range with a diagnosis address of for example 0x45 would be 0x4501 to 0x45ff. + + Setting the mask to `0xFE00` doubles client ID range to 511 clients as the + Hamming weight of the inverted mask is greater by one. With a diagnosis address + of 0x45 the start value of client IDs is 0x4401 as bit 8 in 0x4500 is masked + out. This then yields a client ID range of 0x4400 to 0x45ff. + +* 'network' + Network identifier used to support multiple routing managers on one host. This + setting changes the name of the shared memory segment in `/dev/shm` and the name + of the unix domain sockets in `/tmp/`. Defaults to `vsomeip` meaning the shared + memory will be named `/dev/shm/vsomeip` and the unix domain sockets will be + named `/tmp/vsomeip-$CLIENTID` + +* 'logging' + * 'level' + + Specifies the log level (valid values: _trace_, _debug_, _info_, _warning_, + _error_, _fatal_). + + * 'console' + + Specifies whether logging via console is enabled (valid values: _true, false_). + + * 'file' + + * 'enable' + + Specifies whether a log file should be created (valid values: _true, false_). + * 'path' + + The absolute path of the log file. + + * 'dlt' + + Specifies whether Diagnostic Log and Trace (DLT) is enabled (valid values: + _true, false_). + + * 'version' + + Configures logging of the vsomeip version + + * 'enable' + + Enable or disable cyclic logging of vsomeip version, defaults to true (valid + values: _true, false_) + + * 'interval' + + Configures interval in seconds to log the vsomeip version. Default value is 10. + + * 'memory_log_interval' + + Configures interval in seconds in which the routing manager logs its used + memory. Setting a value greater than zero enables the logging. + + * 'status_log_interval' + + Configures interval in seconds in which the routing manager logs its internal + status. Setting a value greater than zero enables the logging. + +* 'tracing' (optional)<a id="tracing-anchor"></a> + * 'enable' + + Specifies whether the tracing of the SOME/IP messages is enabled + (valid values: _true, false_). Default value is _false_. + If tracing is enabled, the messages will be forwarded to DLT by + the [Trace Connector](#trace-connector) + + * 'sd_enable' + + Specifies whether the tracing of the SOME/IP service discovery messages is + enabled (valid values: _true, false_). Default value is _false_. + + * 'channels (array)' (optional) + + Contains the channels to DLT. + + NOTE: You can set up multiple channels to DLT over that you can forward the + messages. + + * 'name' + + The name of the channel. + + * 'id' + + The id of the channel. + + * 'filters (array)' (optional) + + Contains the filters that are applied on the messages. + + NOTE: You can apply filters respectively filter rules on the messages with + specific criterias and expressions. So only the filtered messages are forwarded + to DLT. + + * 'channel' (optional) + + The id of the channel over that the filtered messages are forwarded to DLT. If + no channel is specified the default channel (TC) is used. If you want to use a + filter in several different channels, you can provide an array of channel ids. + + NOTE: If you use a positive filter with multiple channels, the same message + will be forwared multiple times to DLT. + + * 'matches' (optional) + + Specification of the criteria to include/exclude a message into/from the trace. + You can either specify lists (array) or ranges of matching elements. + + A list may contain single identifiers which match all messages from/to all + instances of the corresponding service or tuples consisting of service-, + instance- and method-identifier. 'any' may be used as a wildcard for matching + all services, instances or methods. + + A range is specified by two tuples "from" and "to", each consisting of + service-, instance-and method-identifier. All messages with service-, + instance-and method-identifiers that are greater than or equal to "from" + and less than or equal to "to" are matched. + + * 'type' (optional) + + Specifies the filter type (valid values: "positive", "negative", "header-only"). + When a positive filter is used and a message matches one of the filter rules, + the message will be traced/forwarded to DLT. With a negative filter messages + can be excluded. So when a message matches one of the filter rules, the message + will not be traced/forwarded to DLT. Default value is "positive". The value + "header-only" implies the filter is also considered "positive". + +* 'applications (array)' + + Contains the applications of the host system that use this config file. + + * 'name' + + The name of the application. + + * 'id' + + The id of the application. Usually its high byte is equal to the diagnosis address. In this + case the low byte must be different from zero. Thus, if the diagnosis address is 0x63, valid + values range from 0x6301 until 0x63FF. It is also possible to use id values with a high byte + different from the diagnosis address. + + * 'max_dispatchers' (optional) + + The maximum number of threads that shall be used to execute the application callbacks. Default is 10. + + * 'max_dispatch_time' (optional) + + The maximum time in ms that an application callback may consume before the callback is + considered to be blocked (and an additional thread is used to execute pending + callbacks if max_dispatchers is configured greater than 0). The default value if not specified is 100ms. + + * 'max_detached_thread_wait_time' (optional) + + The maximum time in seconds that an application will wait for a detached dispatcher thread + to finish executing. The default value if not specified is 5s. + + * 'threads' (optional) + + The number of internal threads to process messages and events within an application. + Valid values are 1-255. Default is 2. + + * 'io_thread_nice' (optional) + + The nice level for internal threads processing messages and events. POSIX/Linux only. + For actual values refer to nice() documentation. + + * 'request_debounce_time' (optional) + + Specifies a debounce-time interval in ms in which request-service messages are sent to + the routing manager. If an application requests many services in short same time + the load of sent messages to the routing manager and furthermore the replies from the + routing manager (which contains the routing info for the requested service if available) + can be heavily reduced. The default value if not specified is 10ms. + + * 'plugins' (optional array) + + Contains the plug-ins that should be loaded to extend the functionality of vsomeip. + + * 'name' + + The name of the plug-in. + + * 'type' + + The plug-in type (valid values: _application_plugin_). + + An application plug-in extends the functionality on application level. It gets informed + by vsomeip over the basic application states (INIT/START/STOP) and can, based on these + notifications, access the standard "application"-API via the runtime. + +* `services` (array) + + Contains the services of the service provider. + + * `service` + + The id of the service. + + * `instance` + + The id of the service instance. + + * `protocol` (optional) + + The protocol that is used to implement the service instance. The default setting + is _someip_. If a different setting is provided, vsomeip does not open the specified + port (server side) or does not connect to the specified port (client side). Thus, + this option can be used to let the service discovery announce a service that is + externally implemented. + + * `unicast` (optional) + + The unicast that hosts the service instance. + + NOTE: The unicast address is needed if external service instances shall be used, + but service discovery is disabled. In this case, the provided unicast address + is used to access the service instance. + + * `reliable` + + Specifies that the communication with the service is reliable respectively the + TCP protocol is used for communication. + + * `port` + + The port of the TCP endpoint. + + * `enable-magic-cookies` + + Specifies whether magic cookies are enabled (valid values: _true_, _false_). + + * `unreliable` + + Specifies that the communication with the service is unreliable respectively the + UDP protocol is used for communication (valid values: the _port_ of the UDP + endpoint). + + * `events` (array) + + Contains the events of the service. + + * `event` + + The id of the event. + + * `is_field` + + Specifies whether the event is of type field. + + NOTE: A field is a combination of getter, setter and notification event. It + contains at least a getter, a setter, or a notifier. The notifier sends an event + message that transports the current value of a field on change. + + * `is_reliable` + + Specifies whether the communication is reliable respectively whether the event + is sent with the TCP protocol (valid values: _true_,_false_). + + If the value is _false_ the UDP protocol will be used. + + * `eventgroups` (array) + + Events can be grouped together into on event group. For a client it is thus + possible to subscribe for an event group and to receive the appropriate events + within the group. + + * `eventgroup` + + The id of the event group. + + * `events` (array) + + Contains the ids of the appropriate events. + + * `multicast` + + Specifies the multicast that is used to publish the eventgroup. + + * `address` + + The multicast address. + + * `port` + + The multicast port. + + * `threshold` + + Specifies when to use multicast and when to use unicast to send a notification event. + Must be set to a non-negative number. If it is set to zero, all events of the eventgroup + will be sent by unicast. Otherwise, the events will be sent by unicast as long as the + number of subscribers is lower than the threshold and by multicast if the number + of subscribers is greater or equal. This means, a threshold of 1 will lead to all events + being sent by multicast. The default value is _0_. + + * `debounce-times` (object) + + Used to configure the nPDU feature. This is described in detail in + [vSomeIP nPDU feature](#vsomeip-npdu-feature). + + * `someip-tp` (object) + + Used to configure the SOME/IP-TP feature. There's an example available at + [SOME/IP-TP](#someip-tp). + + * `service-to-client` (array) + + Contains the IDs for responses, fields and events which are sent from the node + to a remote client which can be segmented via SOME/IP-TP if they exceed the + maximum message size for UDP communication. If an ID isn't listed here the + message will otherwise be dropped if the maximum message size is exceeded. + + * `client-to-service` (array) + + Contains the IDs for requests, which are sent from the node + to a remote service which can be segmented via SOME/IP-TP if they exceed the + maximum message size for UDP communication. If an ID isn't listed here the + message will otherwise be dropped if the maximum message size is exceeded. + +* `clients` (array) + + The client-side ports that shall be used to connect to a specific service. + For each service, an array of ports to be used for reliable / unreliable + communication can be specified. vsomeip will take the first free port of + the list. If no free port can be found, the connection will fail. If + vsomeip is asked to connect to a service instance without specified port(s), + the port will be selected by the system. This implies that the user has + to ensure that the ports configured here do not overlap with the ports + automatically selected by the IP stack. + + * `service` + * `instance` + + Together they specify the service instance the port configuration shall be applied to. + + * `reliable` (array) + + The list of client ports to be used for reliable (TCP) communication to the given + service instance. + + * `unreliable` (array) + + The list of client ports to be used for unreliable (UDP) communication to the given + service instance. + + Additionally there is the possibility to configure mappings between ranges of client + ports and ranges of remote service ports. + (If a client port is configured for a specific service / instance, the port range mapping is ignored) + + * `reliable_remote_ports` + + Specifies a range of reliable remote service ports + + * `unreliable_remote_ports` + + Specifies a range of unreliable remote service ports + + * `reliable_client_ports` + + Specifies the range of reliable client ports to be mapped to the reliable_remote_ports range + + * `unreliable_client_ports` + + Specifies the range of unreliable client ports to be mapped to the unreliable_remote_ports range + + * `first` + + Specifies the lower bound of a port range + + * `last` + + Specifies the upper bound of a port range + +* `payload-sizes` (array) + + Array to limit the maximum allowed payload sizes per IP and port. If not + specified otherwise the allowed payload sizes are unlimited. The settings in + this array only affect communication over TCP. To limit the local payload size + `max-payload-size-local` can be used. + + * `unicast` (optional) + + On client side: the IP of the remote service for which the payload size should + be limited. + + On service side: the IP of the offered service for which the payload size for + receiving and sending should be limited. + + * `ports` (array) + + Array which holds pairs of port and payload size statements. + + * `port` + + On client side: the port of the remote service for which the payload size should + be limited. + + On service side: the port of the offered service for which the payload size for + receiving and sending should be limited. + + * `max-payload-size` + + On client side: the payload size limit in bytes of a message sent to the + remote service hosted on beforehand specified IP and port. + + On service side: the payload size limit in bytes of messages received and sent + by the service offered on previously specified IP and port. + + If multiple services are hosted on the same port they all share the limit + specified. + +* `max-payload-size-local` + + The maximum allowed payload size for node internal communication in bytes. By + default the payload size for node internal communication is unlimited. It can be + limited via this setting. + +* `max-payload-size-reliable` + + The maximum allowed payload size for TCP communication in + bytes. By default the payload size for TCP communication is + unlimited. It can be limited via this setting. + +* `max-payload-size-unreliable` + + The maximum allowed payload size for UDP communication via SOME/IP-TP in + bytes. By default the payload size for UDP via SOME/IP-TP communication is + unlimited. It can be limited via this setting. This setting only applies for + SOME/IP-TP enabled methods/events/fields (otherwise the UDP default of 1400 + bytes applies). See [SOME/IP-TP](#someip-tp) for an example configuration. + +* `endpoint-queue-limits` (array) + + Array to limit the maximum allowed size in bytes of cached outgoing messages per + IP and port (message queue size per endpoint). If not specified otherwise the + allowed queue size is unlimited. The settings in this array only affect external + communication. To limit the local queue size `endpoint-queue-limit-local` can + be used. + + * `unicast` + + On client side: the IP of the remote service for which the queue size of sent + requests should be limited. + + On service side: the IP of the offered service for which the queue size for + sent responses should be limited. This IP address is therefore + identical to the IP address specified via `unicast` setting on top level of the + json file. + + * `ports` (array) + + Array which holds pairs of port and queue size statements. + + * `port` + + On client side: the port of the remote service for which the queue size of sent + requests should be limited. + + On service side: the port of the offered service for which the queue size for + send responses should be limited. + + * `queue-size-limit` + + On client side: the queue size limit in bytes of messages sent to the + remote service hosted on beforehand specified IP and port. + + On service side: the queue size limit in bytes for responses sent by the service + offered on previously specified IP and port. + + If multiple services are hosted on the same port they all share the limit + specified. + +* `endpoint-queue-limit-external` + + Setting to limit the maximum allowed size in bytes of cached outgoing messages + for external communication (message queue size per endpoint). By default the + queue size for external communication is unlimited. It can be limited via this + setting. Settings done in the `endpoint-queue-limits` array override this + setting. + +* `endpoint-queue-limit-local` + + Setting to limit the maximum allowed size in bytes of cached outgoing messages + for local communication (message queue size per endpoint). By default the queue + size for node internal communication is unlimited. It can be limited via this + setting. + +* `buffer-shrink-threshold` + + The number of processed messages which are half the size or smaller than the + allocated buffer used to process them before the memory for the buffer is + released and starts to grow dynamically again. This setting can be useful in + scenarios where only a small number of the overall messages are a lot bigger + then the rest and the memory allocated to process them should be released in a + timely manner. If the value is set to zero the buffer sizes aren't reseted and + are as big as the biggest processed message. (default is 5) + + Example: `buffer-shrink-threshold` is set to 50. A message with 500 bytes has to + be processed and the buffers grow accordingly. After this message 50 consecutive + messages smaller than 250 bytes have to be processed before the buffer size is + reduced and starts to grow dynamically again. + +* `tcp-restart-aborts-max` + + Setting to limit the number of TCP client endpoint restart aborts due to unfinished TCP handshake. + After the limit is reached, a forced restart of the TCP client endpoint is done if the connection attempt is still pending. + +* `tcp-connect-time-max` + + Setting to define the maximum time until the TCP client endpoint connection attempt should be finished. + If `tcp-connect-time-max` is elapsed, the TCP client endpoint is forcely restarted if the connection attempt is still pending. + +* `udp-receive-buffer-size` + + Specifies the size of the socket receive buffer (`SO_RCVBUF`) used for + UDP client and server endpoints in bytes. (default: 1703936) + +* `internal_services` (optional array) + + Specifies service/instance ranges for pure internal service-instances. + This information is used by vsomeip to avoid sending Find-Service messages + via the Service-Discovery when a client is requesting a not available service- + instance. Its can either be done on service/instance level or on service level + only which then includes all instance from 0x0000-0xffff. + + * `first` + + The lowest entry of the internal service range. + + * `service` + + The lowest Service-ID in hex of the internal service range. + + * `instance` (optional) + + The lowest Instance-ID in hex of a internal service-instance range. + If not specified the lowest Instance-ID is 0x0000. + + * `last` + + The highest entry of the internal service range. + + * `service` + + The highest Service-ID in hex of a internal service range. + + * `instance` (optional) + + The highest Instance-ID in hex of a internal service-instance range. + If not specified the highest Instance-ID is 0xFFFF. + +* `debounce` (optional array) + + Events/fields sent by external devices will be forwarded to the + applications only if a configurable function evaluates to true. The + function checks whether the event/field payload has changed and whether + a specified interval has been elapsed since the last forwarding. + +* `service` + + Service ID which hosts the events to be debounced. + + * `instance` + + Instance ID which hosts the events to be debounced. + + * `events` + + Array of events which shall be debounced based on the following + configuration options. + + * `event` + + Event ID. + + * `on_change` + + Specifies whether the event is forwarded on + payload change or not. (valid values: _true_, _false_). + Default is _false_. + + * `ignore` + + Array of payload indexes with given bit mask (optional) + to be ignored in payload change evaluation. + Instead of specifying an index / bitmask pair, one can only define the payload index + which shall be ignored in the evaluation. + + * `index` + + Payload index to be checked with given bitmask. + + * `mask` + + 1Byte bitmask applied to byte at given payload index. + Example mask: 0x0f ignores payload changes in low nibble of the byte at given index. + + * `interval` + + Specifies if the event shall be debounced based on elapsed time interval. + (valid values: _time in ms_, _never_). Default is _never_. + + * `on_change_resets_interval` (optional) + + Specifies if interval timer is reset when payload change was detected. + (valid values: _false_, _true_). Defaults to _false_. + + * `send_current_value_after` (optional) + + Specifies if last message should be sent after interval timeout. + (valid values: _false_, _true_). Defaults to _false_. + +* `routing` (optional) + + Specifies the properties of the routing. Either a string that specifies the application that hosts the + routing component or a structure that specifies all properties of the routing. If the routing is not + specified, the first started application will host the routing component. + + * `host` + + Properties of the routing manager. + + * `name` + + Name if the application that hosts the routing component. + + * `uid` + + User identifier of the process that runs the routing component. Must be specified if credential checks + are enabled by _check_credentials_ set to true. + + * `gid` + + Group identifier of the process that runs the routing component. Must be specified if credential checks + are enabled by _check_credentials_ set to true. + + * `unicast` (optional) + + The unicast address that shall be used by the routing manager, if the internal communication shall be done + by using TCP connections. + + * `port` (optional) + + The port that shall be used by the routing manager, if the internal communication shall be done + by using TCP connections. + + * `guests` (optional) + + Properties of all applications that do not host the routing component, if the internal communication shall be + done using TCP connections. + + * `unicast` + + The unicast address that shall be used by the applications to connect to the routing manager. + + * `ports` + + A set of port ranges that shall be used to connect to the routing manager per user identifier/group identifier. + Either specify uid, gid and ranges, or only a set of port ranges. If uid and gid are not explicitly specified, + they default to any. Each client application requires two ports, one for receiving messages from other + applications and one to send messages to other applications. + + * `uid` + + User identifier + + * `gid` + + Group identifier + + * `ranges` + + Set of port ranges. Each entry consists of a `first`, `last` pair that determines the first and the last port + of a port range. + + * `first` + + First port of a port range + + * `last` + + Last port of a port range + + NOTE: Each configured port range must contain an even number of ports. If an even port number is configured + to be the routing host port, the first port in the range must also be even. If an uneven port number is + configured to be the routing host port, the first port in the range must also be uneven. + +* `routing-credentials` (deprecated) + + The UID / GID of the application acting as routing manager. + (Must be specified if credentials checks are enabled using _check_credentials_ set to _true_ in order to successfully check the routing managers credentials passed on connect) + + * `uid` + + The routing managers UID. + + * `gid` + + The routing managers GID. + +* `shutdown_timeout` + + Configures the time in milliseconds local clients wait for acknowledgement of + their deregistration from the routing manager during shutdown. Defaults to + 5000ms. + +* `warn_fill_level` + + The routing manager regulary checks the fill level of the send buffers to its + clients. This variable defines the minimum fill level in percent that leads to + a warning being logged. Defaults to 67. + +* `service-discovery` + + Contains settings related to the Service Discovery of the host application. + + * `enable` + + Specifies whether the Service Discovery is enabled (valid values: _true_, + _false_). The default value is _true_. + + * `multicast` + + The multicast address which the messages of the Service Discovery will be sent + to. The default value is _224.0.0.1_. + + * `port` + + The port of the Service Discovery. The default setting is _30490_. + + * `protocol` + + The protocol that is used for sending the Service Discovery messages (valid + values: _tcp_, _udp_). The default setting is _udp_. + + * `initial_delay_min` + + Minimum delay before first offer message. + + * `initial_delay_max` + + Maximum delay before first offer message. + + * `repetitions_base_delay` + + Base delay sending offer messages within the repetition phase. + + * `repetitions_max` + + Maximum number of repetitions for provided services within the + repetition phase. + + * `ttl` + + Lifetime of entries for provided services as well as consumed services and eventgroups. + + * `ttl_factor_offers` (optional array) + + Array which holds correction factors for incoming remote offers. If a value + greater than one is specified for a service instance, the TTL field of the + corresponding service entry will be multiplied with the specified factor. + + Example: An offer of a service is received with a TTL of 3 sec and the TTL + factor is set to 5. The remote node stops offering the service w/o sending a + StopOffer message. The service will then expire (marked as unavailable) 15 seconds + after the last offer has been received. + + * `service` + + The id of the service. + + * `instance` + + The id of the service instance. + + * `ttl_factor` + + TTL correction factor + + * `ttl_factor_subscriptions` (optional array) + + Array which holds correction factors for incoming remote subscriptions. If a + value greater than one is specified for a service instance, the TTL field of the + corresponding eventgroup entry will be multiplied with the specified factor. + + Example: A remote subscription to an offered service is received with a TTL of 3 + sec and the TTL factor is set to 5. The remote node stops resubscribing to the + service w/o sending a StopSubscribeEventgroup message. The subscription will + then expire 15 seconds after the last resubscription has been received. + + * `service` + + The id of the service. + + * `instance` + + The id of the service instance. + + * `ttl_factor` + + TTL correction factor + + * `cyclic_offer_delay` + + Cycle of the OfferService messages in the main phase. + + + * `request_response_delay` + + Minimum delay of a unicast message to a multicast message for + provided services and eventgroups. + + + * `offer_debounce_time` + + Time which the stack collects new service offers before they enter the + repetition phase. This can be used to reduce the number of + sent messages during startup. The default setting is _500ms_. + +* 'suppress_missing_event_logs' + + Used to filter the log message `deliver_notification: Event [1234.5678.80f3] + is not registered. The message is dropped.` that occurs whenever vSomeIP + receives an event without having a corresponding object being registered. + +```json +... +"suppress_missing_event_logs" : +[ + { + "service" : "0x0023", + "instance" : "0x0001", + "events" : [ "0x8001", "0x8002", + { + "first" : "0x8010", + "last" : "0x801f" + }, + "0x8020" ] + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : [ "0x8005", "0x8006" ] + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : [ "0x8105", "0x8106" ] + }, + { + // no "events" --> ignore all(!) events of these services + "service" : "any", + "instance" : "0x00f2" + }, + { + "service" : "0x0102", + "instance" : "any", + "events" : [ "0x8005", "0x8006" ] + } +] +``` + +* `watchdog` (optional) + + The Watchdog sends periodically pings to all known local clients. + If a client isn't responding within a configurred time/amount of pongs + the watchdog deregisters this application/client. + If not configured the watchdog isn't activated. + + * `enable` + + Specifies whether the watchdog is enabled or disabled. + (valid values: _true, false_), (default is _false_). + + * `timeout` + + Specifies the timeout in ms the watchdog gets activated if a ping + isn't answered with a pong by a local client within that time. + (valid values: _2 - 2^32_), (default is _5000_ ms). + + * `allowed_missing_pongs` + + Specifies the amount of allowed missing pongs. + (valid values: _1 - 2^32_), (default is _3_ pongs). + + +* `supports_selective_broadcasts` (optional array) + + This nodes allow to add a list of IP addresses on which CAPI-Selective-Broadcasts feature is supported. + If not specified the feature can't be used and the subscription behavior of the stack is same as with + normal events. + + * `address` + + Specifies an IP-Address (in IPv4 or IPv6 notation) on which the "selective"-feature is supported. + Multiple addresses can be configured. + +# Security + +vsomeip has a security implementation based on UNIX credentials. +If activated every local connection is authenticated during connect using the standard UNIX credential passing mechanism. +During authentication a client transfers its client identifier together with its credentials (UID / GID) to the server which is then matched against the configuration. +If received credentials don't match the policy the socket will be immediately closed by the server and an message is logged. +If accepted the client identifier is bound to the receiving socket and can therefore be used to do further security checks on incoming messages (vsomeip messages as well as internal commands). + +In general clients can be configured to be allowed/denied to request (means communicate with) and offer different service instances. +Every incoming vsomeip message (request/response/notification) as well as offer service requests or local subscriptions are then checked against the policy. +If an incoming vsomeip message or another operation (e.g. offer/subscribe) violates the configured policies it is skipped and a message is logged. + +Furthermore if an application receives informations about other clients/services in the system, it must be received from the authenticated routing manager. +This is to avoid malicious applications faking the routing manager and therefore being able to wrongly inform other clients about services running on the system. +Therefore, whenever the "security" tag is specified, the routing manager (e.g. routingmanagerd/vsomeipd) must be a configured application with a fixed client identifier. +See chapter "Configuration File Structure" on how to configure an application to use a specific client identifier. + +Credential passing is only possible via Unix-Domain-Sockets and therefore only available for local communication. +However if security is activated method calls from remote clients to local services are checked as well which means remote clients needs to be explicitly allowed. +Such a policy looks same in case for local clients except the _credentials_ tag can be skipped. + +## Security configuration + +The available configuration switches for the security feature are: + +* `security` (optional) + + NOTE: As long as no _security_ node exists, the security implementation is switched off. This also means, + no external security library will be loaded and used. + + If specified the credential passing mechanism is activated. However no credential or security checks are done as long as + _check_credentials_ isn't set to _true_, but the routing manager client ID must be configured if security tag is specified. + If _check_credentials_ is set to _true_, the routing managers UID and GID needs to be specified using _routing-credentials_ tag. + + * `check_credentials` (optional) + + Specifies whether security checks are active or not. This includes credentials checks on connect as well as all policies checks configured in follow. + (valid values: _true, false_), (default is _false_). + + * `allow_remote_clients` (optional) + + Specifies whether incoming remote requests / subscriptions are allowed to be sent to a local proxy / client. + If not specified, all remote requests / subscriptions are allowed to be received by default. + (valid values are 'true' and 'false') + + * `policies` (array) + + Specifies the security policies. Each policy at least needs to specify _allow_ or _deny_. + + * `credentials` + + Specifies the credentials for which a security policy will be applied. + If _check_credentials_ is set to _true_ the credentials of a local application needs to be specified correctly to ensure local socket authentication can succeed. + + * `uid` + + Specifies the LINUX user id of the client application as decimal number. + As a wildcard "any" can be used. + + * `gid` + + Specifies the LINUX group id of the client application as decimal number. + As a wildcard "any" can be used. + + * `allow` / `deny` (optional) + + Specifies whether the LINUX user and group ids are allowed or denied for the policy. + + 1. `uid` (array) + + Specifies a list of LINUX user ids. These may either be specified as decimal numbers or as ranges. Ranges + are specified by the first and the last valid id (see example below). + + 2. `gid` (array) + + Specifies a list of LINUX group ids. These may either be specified as decimal numbers or as ranges. Ranges + are specified by the first and the last valid id (see example below). + + * `allow` / `deny` + + This tag specifies either _allow_ or _deny_ depending on white- or blacklisting is needed. Specifing _allow_ and _deny_ entries in one policy is therefore not allowed. + With _allow_ a whitelisting of what is allowed can be done which means an empty _allow_ tag implies everything is denied. + With _deny_ a blacklisting of what is allowed can be done which means an empty _deny_ tag implies everything is allowed. + + * `requests` (array) + + Specifies a set of service instance pairs which the above client application using the credentials above is allowed/denied to communicate with. + + 1. `service` + + Specifies a service for the _requests_. + + 2. `instance` (deprecated) + + Specifies a instance for the _requests_ + As a wildcard "any" can be used which means a range from instance ID 0x01 to 0xFFFF + which also implies a method ID range from 0x01 to 0xFFFF. + + 3. `instances` (array) + + Specifies a set of instance ID and method ID range pairs which are allowed/denied to communicate with. + If the `ids` tag below is not used to specify allowed/denied requests on method ID level one can also + only specify a a set of instance ID ranges which are allowed/denied to be requested analogous to the + allowed/denied `offers` section. + If no method IDs are specified, the allowed/denied methods are by default a range from 0x01 to 0xFFFF. + + 1. `ids` + + Specifies a set of instance ID ranges which are allowed/denied to communicate with. + It is also possible to specify a single instance ID as array element without giving an upper / lower range bound. + As a wildcard "any" can be used which means a range from instance ID 0x01 to 0xFFFF. + + `first` - The lower bound of the instance range. + + `last` - The upper bound of the instance range. + + 2. `methods` + + Specifies a set of method ID ranges which are allowed/denied to communicate with. + It is also possible to specify a single method ID as array element without giving an upper / lower range bound. + As a wildcard "any" can be used which means a range from method ID 0x01 to 0xFFFF. + + `first` - The lower bound of the method range. + + `last` - The upper bound of the method range. + + * `offers` (array) + + Specifies a set of service instance pairs which are allowed/denied to be offered by the client application using the credentials above. + + 1. `service` + + Specifies a service for the _offers_. + + 2. `instance` (deprecated) + + Specifies a instance for the _offers_ + As a wildcard "any" can be used which means a range from instance ID 0x01 to 0xFFFF. + + 3. `instances` (array) + + Specifies a set of instance ID ranges which are allowed/denied to be offered by the client application using the credentials above. + It is also possible to specify a single instance ID as array element without giving an upper / lower range bound. + As a wildcard "any" can be used which means a range from instance ID 0x01 to 0xFFFF. + + 1. `first` + + The lower bound of the instance range. + + 2. `last` + + The upper bound of the instance range. + +--- + +## Security configuration example + +```json +... +"security" : +{ + ... + "policies" : + [ + { + ... + "credentials" : + { + "uid" : "44", + "gid" : "any" + }, + "allow" : + [ + "requests" : + [ + { + "service" : "0x6731", + "instance" : "0x0001" + } + ] + ] + }, + { + "credentials" : + { + "deny" : + [ + { + "uid" : [ "1000", { "first" : "1002", "last" : "max" }], + "gid" : [ "0", { "first" : "100", "last" : "243" }, "300"] + }, + { + "uid" : ["55"], + "gid" : ["55"] + } + ] + }, + "allow" : + [ + "offers" : + [ + { + "service" : "0x6728", + "instances" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"] + }, + { + "service" : "0x6729", + "instances" : ["0x88"] + }, + { + "service" : "0x6730", + "instance" : "any" + } + ], + "requests" : + [ + { + "service" : "0x6732", + "instances" : + [ + { + "ids" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }], + "methods" : [ "0x0001", "0x0003", { "first" : "0x8001", "last" : "0x8006" } ] + }, + { + "ids" : [ "0x0009" ], + "methods" : "any" + } + ] + }, + { + "service" : "0x6733", + "instance" : "0x1" + }, + { + "service" : "0x6733", + "instances" : [ "0x0002", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"] + } + ] + ] + } + ] +} +``` + +The config/ folder contains some addition vsomeip configuration files to run the vsomeip +examples with activated security checks. +Additionally there's a security test in the `test/` subfolder which can be used +for further reference. + +They give a basic overview how to use the security related configuration tags described +in this chapter to run a simple request/response or subscribe/notify example locally or +remotely. + +## Security policy extensions + +vsomeip policy extension configuration supports the definition of paths that contain additional +security policies to be loaded whenever a client with a yet unknown hostname connects to a local server endpoint. +The following configuration parameters are available and can be defined in a file named `vsomeip_policy_extensions.json`. + +* `container_policies` (optional array) + + Specifies the additional configuration folders to be loaded for each container hostname / filesystem path pair. + + * `container` + + Specifies the linux hostname. + + * `path` + + Specifies a filesystem path (relative to vsomeip_policy_extensions.json or absolute) which contains + $UID_$GID subfolders that hold a `vsomeip_security.json` file. + + NOTE: ($UID / $GID) is the UID /GID of the vsomeip client application + to which a client from hostname defined with `container`connetcs to. + +## Audit Mode + +vsomeip's security implementation can be put in a so called 'Audit Mode' where +all security violations will be logged but allowed. This mode can be used to +build a security configuration. + +To activate the 'Audit Mode' the 'security' object has to be included in the +json file but the 'check_credentials' switch has to be set to false. For +example: + + +```json + [...] + "services" : + [ + [...] + ], + "security" : + { + "check_credentials" : "false" + }, + "routing" : "service-sample", + [...] +``` + +# Autoconfiguration + +vsomeip supports the automatic configuration of client identifiers and the routing. +The first application that starts using vsomeip will automatically become the +routing manager if it is _not_ explicitly configured. The client identifiers +are generated from the diagnosis address that can be specified by defining +DIAGNOSIS_ADDRESS when compiling vsomeip. vsomeip will use the diagnosis address +as the high byte and enumerate the connecting applications within the low byte +of the client identifier. + +Autoconfiguration of client identifiers isn't meant to be used together with vsomeip Security. +Every client running locally needs to have at least its own credentials configured when security is activated to ensure the credential checks can pass. +Practically that means if a client requests its identifier over the autoconfiguration for which no credentials are configured (at least it isn't known which client identifier is used beforehand) it is impossible for that client to establish a connection to a server endpoint. +However if the credentials for all clients are same it's possible to configure them for the overall (or DIAGNOSIS_ADDRESS) client identifier range to mix autoconfiguration together with activated security. + +# routingmanagerd + +The routingmanagerd is a minimal vsomeip application intended to offer routing +manager functionality on a node where one system wide configuration file is +present. It can be found in the examples folder. + +Example: Starting the daemon on a system where the system wide configuration is +stored under `/etc/vsomeip.json`: + +```bash +VSOMEIP_CONFIGURATION=/etc/vsomeip.json ./routingmanagerd +``` + +When using the daemon it should be ensured that: + +* In the system wide configuration file the routingmanagerd is defined as + routing manager, meaning it contains the line `"routing" : "routingmanagerd"`. + If the default name is overridden the entry has to be adapted accordingly. + The system wide configuration file should contain the information about all + other offered services on the system as well. +* There's no other vsomeip configuration file used on the system which contains + a `"routing"` entry. As there can only be one routing manager per system. + +# vsomeip Hello World + +In this paragraph a Hello World program consisting out of a client and a service +is developed. The client sends a message containing a string to the service. +The service appends the received string to the string `Hello` and sends it back +to the client. +Upon receiving a response from the service the client prints the payload of the +response ("Hello World"). +This example is intended to be run on the same host. + +All files listed here are contained in the `examples\hello_world` subdirectory. + +## Build instructions + +The example can build with its own CMakeFile, please compile the vsomeip stack +before hand as described in [Compilation](#compilation). Then compile the example starting +from the repository root directory as followed: + +```bash +cd examples/hello_world +mkdir build +cd build +cmake .. +make +``` + +## Starting and expected output +### Starting and expected output of service + +```bash +$ VSOMEIP_CONFIGURATION=../helloworld-local.json \ + VSOMEIP_APPLICATION_NAME=hello_world_service \ + ./hello_world_service +2015-04-01 11:31:13.248437 [info] Using configuration file: ../helloworld-local.json +2015-04-01 11:31:13.248766 [debug] Routing endpoint at /tmp/vsomeip-0 +2015-04-01 11:31:13.248913 [info] Service Discovery disabled. Using static routing information. +2015-04-01 11:31:13.248979 [debug] Application(hello_world_service, 4444) is initialized. +2015-04-01 11:31:22.705010 [debug] Application/Client 5555 got registered! +``` + +### Starting and expected output of client + +```bash +$ VSOMEIP_CONFIGURATION=../helloworld-local.json \ + VSOMEIP_APPLICATION_NAME=hello_world_client \ + ./hello_world_client +2015-04-01 11:31:22.704166 [info] Using configuration file: ../helloworld-local.json +2015-04-01 11:31:22.704417 [debug] Connecting to [0] at /tmp/vsomeip-0 +2015-04-01 11:31:22.704630 [debug] Listening at /tmp/vsomeip-5555 +2015-04-01 11:31:22.704680 [debug] Application(hello_world_client, 5555) is initialized. +Sending: World +Received: Hello World +``` + +## CMakeFile + +[examples/hello_world/CMakeLists.txt](../examples/hello_world/CMakeLists.txt) + +## Configuration File For Client and Service + +[examples/hello_world/helloworld-local.json](../examples/hello_world/helloworld-local.json) + +## Service + +[examples/hello_world/hello_world_service_main.cpp](../examples/hello_world/hello_world_service_main.cpp) + +The service example results in the following program execution: + +### Main + +1. *main()* + + First the application is initialized. After the initialization is + finished the application is started. + +### Initialization + +2. *init()* + + The initialization contains the registration of a message + handler and an event handler. + + The message handler declares a callback (__on_message_cbk__) for messages that + are sent to the specific service (specifying the service id, the service + instance id and the service method id). + + The event handler declares a callback (__on_event_cbk__) for events that occur. + One event can be the successful registration of the application at the runtime. + +### Start + +3. *start()* + + The application will be started. This function only returns when the application + will be stopped. + +### Callbacks + +4. *on_state_cbk()* + + This function is called by the application when an state change occurred. If + the application was successfully registered at the runtime then the specific + service is offered. + +5. *on_message_cbk()* + + This function is called when a message/request from a client for the specified + service was received. + + First a response based upon the request is created. + Afterwards the string 'Hello' will be concatenated with the payload of the + client's request. + After that the payload of the response is created. The payload data is set with + the previously concatenated string. + Finally the response is sent back to the client and the application is stopped. + +### Stop + +6. *stop()* + + This function stops offering the service, unregister the message and the event + handler and shuts down the application. + +## Client + +[examples/hello_world/hello_world_client_main.cpp](../examples/hello_world/hello_world_client_main.cpp) + +The client example results in the following program execution: + +### Main + +1. *main()* + + First the application is initialized. After the initialization is finished the + application is started. + +### Initialization + +2. *init()* + + The initialization contains the registration of a message handler, an event + handler and an availability handler. + + The event handler declares again a callback (__on_state_cbk__) for state changes + that occur. + + The message handler declares a callback (__on_message_cbk__) for messages that + are received from any service, any service instance and any method. + + The availability handler declares a callback (__on_availability_cbk__) which is + called when the specific service is available (specifying the service id and the + service instance id). + +### Start + +3. *start()* + + The application will be started. This function only returns when the application + will be stopped. + +### Callbacks + +4. *on_state_cbk()* + + This function is called by the application when an state change occurred. If the + application was successfully registered at the runtime then the specific service + is requested. + +5. *on_availability_cbk()* + + This function is called when the requested service is available or no longer + available. + + First there is a check if the change of the availability is related to the + 'hello world service' and the availability changed to true. + If the check is successful a service request is created and the appropriate + service information are set (service id, service instance id, service method + id). + After that the payload of the request is created. The data of the payload is + 'World' and will be set afterwards. + Finally the request is sent to the service. + +6. *on_message_cbk()* + + This function is called when a message/response was received. + If the response is from the requested service, of type 'RESPONSE' and the return + code is 'OK' then the payload of the response is printed. Finally the + application is stopped. + +### Stop + +7. *stop()* + +This function unregister the event and the message handler and shuts down the +application. + +# Trace Connector +## Overview/Prerequisites + +The Trace Connector is used to forward the internal messages that are sent over +the Unix Domain Sockets to DLT. + +Thus, it requires that DLT is installed and the DLT module can be found in the +context of CMake. + +## Configuration +### Static Configuration + +The Trace Connector can be configured statically over the *tracing* point of the +[Configuration File Structure](#tracing-anchor) + +### Example 1 (Minimal Configuration) + +```json +{ + ... + + "tracing" : + { + "enable" : "true" + }, + + ... +``` + +This is the minimal configuration of the Trace Connector. This just enables the +tracing and all of the sent internal messages will be traced/forwarded to DLT. + +### Example 2 (Using Filters) + +```json +{ + ... + + "tracing" : + { + "enable" : "true", + "channels" : + [ + { + "name" : "My channel", + "id" : "MC" + } + ], + "filters" : [ + { + "channel" : "MC", + "matches" : [ { "service" : "0x1234", "instance" : "any", "method" : "0x80e8" } ], + "type" : "positive" + } + ] + }, + + ... +``` + +As it is a positive filter, the example filter ensures that only messages +representing method '0x80e8' from instances of service '0x1234' will be +forwarded to the DLT. If it was specified as a negative filter, all messages +except messages representing method '0x80e8' from instances of service +'0x1234' would be forwarded to the DLT. + +The general filter rules are: + +* The default filter is a positive filter for all messages. +* The default filter is active on a channel as long as no other positive +filter is specified. +* Negative filters block matching messages. Negative filters overrule +positive filters. Thus, as soon as a messages matches a negative filter it +will not be forwarded. +* The identifier '0xffff' is a wildcard that matches any service, instance or method. +The keyword 'any' can be used as a replacement for '0xffff'. +* Wildcards must not be used within range filters. + +### Dynamic Configuration + +The Trace Connector can also be configured dynamically over its interfaces. +You need to include '<vsomeip/trace.hpp>' to access its public interface. + +### Example: + +```c++ + // get trace connector + std::shared_ptr<vsomeip::trace::connector> its_connector + = vsomeip::trace::connector::get(); + + // add channel + std::shared_ptr<vsomeip::trace::channel> its_channel + = its_connector->create_channel("MC", "My channel"); + + // add filter rule + vsomeip::trace::match_t its_match + = std::make_tuple(0x1234, 0xffff, 0x80e8); + vsomeip::trace::filter_id_t its_filter_id + = its_channel->add_filter(its_match, true); + + // init trace connector + its_connector->init(); + + // enable trace connector + its_connector->set_enabled(true); + + // remove the filter + its_channel->remove_filter(its_filter_id); +``` + +# vsomeip nPDU feature + +This is the add-on documentation for the nPDU feature, aka. _Zugverfahren_. + +The nPDU feature can be used to reduce network load as it enables the vsomeip +stack to combine multiple vsomeip messages in one single ethernet frame. + +Some general _important_ things regarding the nPDU feature first: + +* Due to its nature the nPDU feature trades lower network load for speed. +* As the nPDU feature requires some settings which are not transmitted +through the service discovery, it's *not* sufficient anymore to have an json +file without a "services" section on the client side. +* As the client- and server-endpoints of a node are managed by the routing + manager (which is the application entered at "routing" in the json file) + the nPDU feature settings *always* have to be defined in the json file used by + the application acting as routing manager. +* The nPDU feature timings are defined in milliseconds. +* Node internal communication over UNIX domain sockets is not affected by the + nPDU feature. +* If the debounce times configuration for a method in the json file is missing + or incomplete the default values are used: 2ms debounce time and 5ms max + retention time. The global default values can be overwritten via the + `npdu-default-timings` json object. + +## Configuration + +There are two parameters specific for the nPDU feature: + +* *debounce time*: minimal time between sending a message to the same method of + a remote service over the same connection (src/dst address + src/dst port). +* *max retention time*: the maximum time which a message to the same method of a + remote service over the same connection (src/dst address + src/dst port) is + allowed to be buffered on sender side. + +For more information please see the corresponding requirement documents. + + +The nPDU feature specific settings are configured in the json file in the +"services" section on service level in a special _debounce-times_ section: + + +```json +[...] +"services": +[ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "debounce-times": + { + // nPDU feature configuration for this + // service here + } + } +], +[...] +``` + +Additionally nPDU default timings can be configured globally. + +The global default timings can be overwritten via the `npdu-default-timings` +json object. For example the following configuration snippet shows how to set +all default timings to zero: + +```json +{ + "unicast":"192.168.1.9", + [...] + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +### Example 1: One service with one method offered over UDP + +* The service is hosted on IP: 192.168.1.9. +* The service is offered on port 30509 via UDP. +* The service has the ID 0x1000 +* The method has the ID 0x0001 +* The client accesses the service from IP: 192.168.1.77 + +### Service side + +* Debounce time for responses should have a: + * debounce time of 10 milliseconds + * maximum retention time of 100 milliseconds + +```json +{ + "unicast":"192.168.1.9", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "debounce-times": + { + "responses": { + "0x1001" : { + "debounce-time":"10", + "maximum-retention-time":"100" + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +#### Client side + +* Debounce time for requests to the service on 192.168.1.9 should have a: + * debounce time of 20 milliseconds + * maximum retention time of 200 milliseconds + +```json +{ + "unicast":"192.168.1.77", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unicast":"192.168.1.9", // required to mark service as external + "unreliable":"30509", + "debounce-times": + { + "requests": { + "0x1001" : { + "debounce-time":"20", + "maximum-retention-time":"200" + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +### Example 2: One service with two methods offered over UDP + +* The service is hosted on IP: 192.168.1.9. +* The service is offered on port 30509 via UDP. +* The service has the ID 0x1000 +* The method has the ID 0x0001 +* The second method has the ID 0x0002 +* The client accesses the service from IP: 192.168.1.77 + +#### Service side + +* Debounce time for responses should have a: + * debounce time of 10 milliseconds for method 0x1001 and 20 for 0x1002 + * maximum retention time of 100 milliseconds for method 0x1001 and 200 for 0x1002 + +```json +{ + "unicast":"192.168.1.9", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "debounce-times": + { + "responses": { + "0x1001" : { + "debounce-time":"10", + "maximum-retention-time":"100" + }, + "0x1002" : { + "debounce-time":"20", + "maximum-retention-time":"200" + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +#### Client side + +* Debounce time for requests to the service on 192.168.1.9 should have a: + * debounce time of 20 milliseconds for method 0x1001 and 40 for 0x1002 + * maximum retention time of 200 milliseconds for method 0x1001 and 400 for 0x1002 + +```json +{ + "unicast":"192.168.1.77", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unicast":"192.168.1.9", // required to mark service as external + "unreliable":"30509", + "debounce-times": + { + "requests": { + "0x1001" : { + "debounce-time":"20", + "maximum-retention-time":"200" + }, + "0x1002" : { + "debounce-time":"40", + "maximum-retention-time":"400" + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +### Example 3: One service with one method offered over UDP and TCP + +* The service is hosted on IP: 192.168.1.9. +* The service is offered on port 30509 via UDP. +* The service is offered on port 30510 via TCP. +* The service has the ID 0x1000 +* The method has the ID 0x0001 +* The client accesses the service from IP: 192.168.1.77 + +#### Service side + +* Debounce time for responses should have a: + * debounce time of 10 milliseconds + * maximum retention time of 100 milliseconds + * TCP should use the same settings as UDP + +```json +{ + "unicast":"192.168.1.9", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": + { + "responses": { + "0x1001" : { + "debounce-time":"10", + "maximum-retention-time":"100", + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +#### Client side + +* Debounce time for requests to the service on 192.168.1.9 should have a: + * debounce time of 20 milliseconds + * maximum retention time of 200 milliseconds + * TCP should use the same settings as UDP + +```json +{ + "unicast":"192.168.1.77", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unicast":"192.168.1.9", // required to mark service as external + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": + { + "requests": { + "0x1001" : { + "debounce-time":"20", + "maximum-retention-time":"200", + } + } + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +# SOME/IP TP + +With SOME/IP Transport Protocol (TP) it is possible to transport messages which +exceed the UDP payload size limit of 1400 byte. If enabled the message is +segmented and send in multiple UDP datagrams. + +Example configuration: + +* Service 0x1111/0x1 is hosted on 192.168.0.1 on UDP port 40000 +* Client is running on 192.168.0.100 +* The service has two methods with ID: 0x1 and 0x2 which require large requests + and large responses. Additionally the service offers a field with ID 0x8001 + which requires a large payloads as well. +* The maximum payload size on service side should be limited to 5000 bytes. + +Configuration service side: + +```json +{ + "unicast":"192.168.0.1", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x1", + "unreliable":"40000", + "someip-tp": { + "service-to-client": [ + "0x1", "0x2", "0x8001" + ] + } + } + ], + "max-payload-size-unreliable" : "5000", + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +Configuration client side: + +```json +{ + "unicast":"192.168.0.100", + "logging": { [...] }, + "applications": [ [...] ], + "services": + [ + { + "service":"0x1000", + "instance":"0x1", + "unicast":"192.168.0.1", // required to mark service as external + "unreliable":"40000", // required to mark service as external + "someip-tp": { + "client-to-service": [ + "0x1", "0x2" + ] + } + } + ], + "routing":"[...]", + "service-discovery": { [...] } +} +``` + +# Tools +## vsomeip_ctrl + +`vsomeip_ctrl` is a small utility which can be used to send SOME/IP messages +from the commandline. If a response arrives within 5 seconds the response will +be printed. + +* It can be build via `vsomeip_ctrl` make target (`make vsomeip_ctrl`). +* The instance id of the target service has to be passed in hexadecimal + notation. +* The complete message has to be passed in hexadecimal notation. +* See the `--help` parameter for available options. +* If `vsomeip_ctrl` is used to send messages to a remote service and no + `routingmanagerd` is running on the local machine, make sure to pass a json + configuration file where `vsomeip_ctrl` is set as routing manager via + environment variable. +* If `vsomeip_ctrl` is used to send messages to a local service and no + `routingmanagerd` is running on the local machine, make sure to use the same json + configuration file as the local service. + +Example: Calling method with method id 0x80e8 on service with service id 0x1234, +instance id 0x5678: + +```bash +./vsomeip_ctrl --instance 5678 --message 123480e800000015134300030100000000000009efbbbf576f726c6400 +``` + +Example: Sending a message to service with service id 0x1234, instance id +0x5678 and method id 0x0bb8 via TCP + +```bash +./vsomeip_ctrl --tcp --instance 5678 --message 12340bb8000000081344000101010000 +``` diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/examples/CMakeLists.txt new file mode 100644 index 00000000000..3ce54832cbb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +set(EXAMPLE_CONFIG_FILES + "../config/vsomeip.json" + "../config/vsomeip-local.json" + "../config/vsomeip-tcp-client.json" + "../config/vsomeip-tcp-service.json" + "../config/vsomeip-udp-client.json" + "../config/vsomeip-udp-service.json" +) + +# Examples +add_executable(request-sample request-sample.cpp ${EXAMPLE_CONFIG_FILES}) +target_link_libraries(request-sample ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${DL_LIBRARY}) + +add_executable(response-sample response-sample.cpp ${EXAMPLE_CONFIG_FILES}) +target_link_libraries(response-sample ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${DL_LIBRARY}) + +add_executable(subscribe-sample subscribe-sample.cpp ${EXAMPLE_CONFIG_FILES}) +target_link_libraries(subscribe-sample ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${DL_LIBRARY}) + +add_executable(notify-sample notify-sample.cpp ${EXAMPLE_CONFIG_FILES}) +target_link_libraries(notify-sample ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${DL_LIBRARY}) + +add_dependencies(examples request-sample response-sample subscribe-sample notify-sample) + +install ( + TARGETS request-sample response-sample subscribe-sample notify-sample + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin +) + +################################################################################################### diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/Android.bp b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/Android.bp new file mode 100644 index 00000000000..39da095e56b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/Android.bp @@ -0,0 +1,35 @@ +cc_defaults { + name: "vsomeip_hello_world_defaults", + vendor: true, + + cppflags: [ + "-std=c++17", + "-Wno-unused-parameter", + ], + + shared_libs: [ + "libvsomeip3", + "libvsomeip_cfg", + "libvsomeip_e2e", + "libvsomeip_sd", + "liblog", + ], +} + +cc_binary { + name: "vsomeip_hello_world_service", + defaults: ["vsomeip_hello_world_defaults"], + + srcs: [ + "hello_world_service_main.cpp", + ], +} + +cc_binary { + name: "vsomeip_hello_world_client", + defaults: ["vsomeip_hello_world_defaults"], + + srcs: [ + "hello_world_client_main.cpp", + ], +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/CMakeLists.txt new file mode 100644 index 00000000000..d528692e6a2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required (VERSION 3.13) +project (vSomeIPHelloWorld) + +find_package(Threads REQUIRED) + +set(VSOMEIP_NAME "vsomeip3") + +# create_target("executable") +function(create_target executable) + add_library(vsomeip_hello_world_${executable} INTERFACE) + target_sources(vsomeip_hello_world_${executable} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/hello_world_${executable}.hpp" + ) + target_compile_features(vsomeip_hello_world_${executable} INTERFACE cxx_std_17) + + target_include_directories(vsomeip_hello_world_${executable} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) +endfunction() + +# link_target("executable") +function(link_target executable) + add_executable(hello_world_${executable}) + target_sources(hello_world_${executable} PRIVATE hello_world_${executable}_main.cpp) + target_link_libraries(hello_world_${executable} PRIVATE vsomeip_hello_world_${executable} vsomeip3 Threads::Threads) +endfunction() + +include_directories(${VSOMEIP_INCLUDE_DIRS}) + +create_target("service") +create_target("client") + +if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Android") + # This will get us acces to + # VSOMEIP_INCLUDE_DIRS - include directories for vSomeIP + # VSOMEIP_LIBRARIES - libraries to link against + find_package(${VSOMEIP_NAME}) + if (NOT ${VSOMEIP_NAME}_FOUND) + message("${VSOMEIP_NAME} was not found. Please specify vsomeip_DIR") + endif() + + link_target("client") + link_target("service") +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client.hpp new file mode 100644 index 00000000000..5c5381017b0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client.hpp @@ -0,0 +1,143 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <vsomeip/vsomeip.hpp> + +#if defined ANDROID || defined __ANDROID__ +#include "android/log.h" +#define LOG_TAG "hello_world_client" +#define LOG_INF(...) fprintf(stdout, __VA_ARGS__), fprintf(stdout, "\n"), (void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__) +#define LOG_ERR(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n"), (void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__) +#else +#include <cstdio> +#define LOG_INF(...) fprintf(stdout, __VA_ARGS__), fprintf(stdout, "\n") +#define LOG_ERR(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n") +#endif + +static vsomeip::service_t service_id = 0x1111; +static vsomeip::instance_t service_instance_id = 0x2222; +static vsomeip::method_t service_method_id = 0x3333; + +class hello_world_client { +public: + // Get the vSomeIP runtime and + // create a application via the runtime, we could pass the application name + // here otherwise the name supplied via the VSOMEIP_APPLICATION_NAME + // environment variable is used + hello_world_client() : + rtm_(vsomeip::runtime::get()), + app_(rtm_->create_application()) + { + } + + bool init(){ + // init the application + if (!app_->init()) { + LOG_ERR ("Couldn't initialize application"); + return false; + } + + // register a state handler to get called back after registration at the + // runtime was successful + app_->register_state_handler( + std::bind(&hello_world_client::on_state_cbk, this, + std::placeholders::_1)); + + // register a callback for responses from the service + app_->register_message_handler(vsomeip::ANY_SERVICE, + service_instance_id, vsomeip::ANY_METHOD, + std::bind(&hello_world_client::on_message_cbk, this, + std::placeholders::_1)); + + // register a callback which is called as soon as the service is available + app_->register_availability_handler(service_id, service_instance_id, + std::bind(&hello_world_client::on_availability_cbk, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; + } + + void start() + { + // start the application and wait for the on_event callback to be called + // this method only returns when app_->stop() is called + app_->start(); + } + + void on_state_cbk(vsomeip::state_type_e _state) + { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + // we are registered at the runtime now we can request the service + // and wait for the on_availability callback to be called + app_->request_service(service_id, service_instance_id); + } + } + + void on_availability_cbk(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) + { + // Check if the available service is the the hello world service + if(service_id == _service && service_instance_id == _instance + && _is_available) + { + // The service is available then we send the request + // Create a new request + std::shared_ptr<vsomeip::message> rq = rtm_->create_request(); + // Set the hello world service as target of the request + rq->set_service(service_id); + rq->set_instance(service_instance_id); + rq->set_method(service_method_id); + + // Create a payload which will be sent to the service + std::shared_ptr<vsomeip::payload> pl = rtm_->create_payload(); + std::string str("World"); + std::vector<vsomeip::byte_t> pl_data(std::begin(str), std::end(str)); + + pl->set_data(pl_data); + rq->set_payload(pl); + // Send the request to the service. Response will be delivered to the + // registered message handler + LOG_INF("Sending: %s", str.c_str()); + app_->send(rq); + } + } + + void on_message_cbk(const std::shared_ptr<vsomeip::message> &_response) + { + if(service_id == _response->get_service() + && service_instance_id == _response->get_instance() + && vsomeip::message_type_e::MT_RESPONSE + == _response->get_message_type() + && vsomeip::return_code_e::E_OK == _response->get_return_code()) + { + // Get the payload and print it + std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); + std::string resp = std::string( + reinterpret_cast<const char*>(pl->get_data()), 0, + pl->get_length()); + LOG_INF("Received: %s", resp.c_str()); + stop(); + } + } + + void stop() + { + // unregister the state handler + app_->unregister_state_handler(); + // unregister the message handler + app_->unregister_message_handler(vsomeip::ANY_SERVICE, + service_instance_id, vsomeip::ANY_METHOD); + // alternatively unregister all registered handlers at once + app_->clear_all_handler(); + // release the service + app_->release_service(service_id, service_instance_id); + // shutdown the application + app_->stop(); + } + +private: + std::shared_ptr<vsomeip::runtime> rtm_; + std::shared_ptr<vsomeip::application> app_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client_main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client_main.cpp new file mode 100644 index 00000000000..d8cd07d3b1d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_client_main.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <vsomeip/vsomeip.hpp> +#include "hello_world_client.hpp" + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +hello_world_client *hw_cl_ptr(nullptr); + void handle_signal(int _signal) { + if (hw_cl_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + hw_cl_ptr->stop(); + } +#endif + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + hello_world_client hw_cl; +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + hw_cl_ptr = &hw_cl; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (hw_cl.init()) { + hw_cl.start(); + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service.hpp new file mode 100644 index 00000000000..b04cacea324 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service.hpp @@ -0,0 +1,143 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <vsomeip/vsomeip.hpp> +#include <chrono> +#include <thread> +#include <condition_variable> +#include <mutex> + +#if defined ANDROID || defined __ANDROID__ +#include "android/log.h" +#define LOG_TAG "hello_world_service" +#define LOG_INF(...) std::fprintf(stdout, __VA_ARGS__), std::fprintf(stdout, "\n"), (void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__) +#define LOG_ERR(...) std::fprintf(stderr, __VA_ARGS__), std::fprintf(stderr, "\n"), (void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__) +#else +#include <cstdio> +#define LOG_INF(...) std::fprintf(stdout, __VA_ARGS__), std::fprintf(stdout, "\n") +#define LOG_ERR(...) std::fprintf(stderr, __VA_ARGS__), std::fprintf(stderr, "\n") +#endif + +static vsomeip::service_t service_id = 0x1111; +static vsomeip::instance_t service_instance_id = 0x2222; +static vsomeip::method_t service_method_id = 0x3333; + +class hello_world_service { +public: + // Get the vSomeIP runtime and + // create a application via the runtime, we could pass the application name + // here otherwise the name supplied via the VSOMEIP_APPLICATION_NAME + // environment variable is used + hello_world_service() : + rtm_(vsomeip::runtime::get()), + app_(rtm_->create_application()), + stop_(false) + { + stop_thread_ = std::thread{&hello_world_service::stop, this}; + } + + ~hello_world_service() + { + if (std::this_thread::get_id() != stop_thread_.get_id()) { + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + } else { + stop_thread_.detach(); + } + } + + bool init() + { + // init the application + if (!app_->init()) { + LOG_ERR("Couldn't initialize application"); + return false; + } + + // register a message handler callback for messages sent to our service + app_->register_message_handler(service_id, service_instance_id, + service_method_id, + std::bind(&hello_world_service::on_message_cbk, this, + std::placeholders::_1)); + + // register a state handler to get called back after registration at the + // runtime was successful + app_->register_state_handler( + std::bind(&hello_world_service::on_state_cbk, this, + std::placeholders::_1)); + return true; + } + + void start() + { + // start the application and wait for the on_event callback to be called + // this method only returns when app_->stop() is called + app_->start(); + } + + void stop() + { + std::unique_lock<std::mutex> its_lock(mutex_); + while(!stop_) { + condition_.wait(its_lock); + } + std::this_thread::sleep_for(std::chrono::seconds(5)); + // Stop offering the service + app_->stop_offer_service(service_id, service_instance_id); + // unregister the state handler + app_->unregister_state_handler(); + // unregister the message handler + app_->unregister_message_handler(service_id, service_instance_id, + service_method_id); + // shutdown the application + app_->stop(); + } + + void terminate() { + std::lock_guard<std::mutex> its_lock(mutex_); + stop_ = true; + condition_.notify_one(); + } + + void on_state_cbk(vsomeip::state_type_e _state) + { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + // we are registered at the runtime and can offer our service + app_->offer_service(service_id, service_instance_id); + } + } + + void on_message_cbk(const std::shared_ptr<vsomeip::message> &_request) + { + // Create a response based upon the request + std::shared_ptr<vsomeip::message> resp = rtm_->create_response(_request); + + // Construct string to send back + std::string str("Hello "); + str.append( + reinterpret_cast<const char*>(_request->get_payload()->get_data()), + 0, _request->get_payload()->get_length()); + + // Create a payload which will be sent back to the client + std::shared_ptr<vsomeip::payload> resp_pl = rtm_->create_payload(); + std::vector<vsomeip::byte_t> pl_data(str.begin(), str.end()); + resp_pl->set_data(pl_data); + resp->set_payload(resp_pl); + + // Send the response back + app_->send(resp); + // we have finished + terminate(); + } + +private: + std::shared_ptr<vsomeip::runtime> rtm_; + std::shared_ptr<vsomeip::application> app_; + bool stop_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread stop_thread_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service_main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service_main.cpp new file mode 100644 index 00000000000..ca3e8cb8b90 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/hello_world_service_main.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <vsomeip/vsomeip.hpp> +#include "hello_world_service.hpp" + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +hello_world_service *hw_srv_ptr(nullptr); + void handle_signal(int _signal) { + if (hw_srv_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + hw_srv_ptr->terminate(); + } +#endif + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + hello_world_service hw_srv; +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + hw_srv_ptr = &hw_srv; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (hw_srv.init()) { + hw_srv.start(); + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/helloworld-local.json b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/helloworld-local.json new file mode 100644 index 00000000000..bca92c03f51 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/helloworld-local.json @@ -0,0 +1,28 @@ +{ + "unicast": "134.86.56.94", + "logging": { + "level": "debug", + "console": "true" + }, + "applications": [ + { + "name": "hello_world_service", + "id": "0x4444" + }, + { + "name": "hello_world_client", + "id": "0x5555" + } + ], + "services": [ + { + "service": "0x1111", + "instance": "0x2222", + "unreliable": "30509" + } + ], + "routing": "hello_world_service", + "service-discovery": { + "enable": "false" + } +} \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme new file mode 100644 index 00000000000..b55d7f46ec6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme @@ -0,0 +1,104 @@ +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Build instructions for Hello World example +------------------------------------------ + +1. Build whole project at first: +________________________________ +cd <root directory of vSomeIP-Lib>$: + +mkdir build +cd build +cmake .. +make +sudo make install + +2. Build hello_world target +___________________________ +cd <root directory of vSomeIP-Lib>/examples/hello_world$: + +mkdir build +cd build +cmake .. +make + +Running Hello World Example +--------------------------- + +The Hello World Example should be run on the same host. +The network addresses within the configuration files need to be adapted to match +the devices addresses. + +To start the hello world client and service from their build-directory do: + +HOST1: +VSOMEIP_CONFIGURATION=../helloworld-local.json \ +VSOMEIP_APPLICATION_NAME=hello_world_service \ +./hello_world_service + +HOST1: +VSOMEIP_CONFIGURATION=../helloworld-local.json \ +VSOMEIP_APPLICATION_NAME=hello_world_client \ +./hello_world_client + +Expected output service +----------------------- +2023-11-03 16:40:31.974886 [info] Using configuration file: "../helloworld-local.json". +2023-11-03 16:40:31.013979 [info] Parsed vsomeip configuration in 17ms +2023-11-03 16:40:31.014674 [info] Configuration module loaded. +2023-11-03 16:40:31.014741 [info] Security disabled! +2023-11-03 16:40:31.014776 [info] Initializing vsomeip (3.4.9.1) application "hello_world_service". +2023-11-03 16:40:31.017415 [info] Instantiating routing manager [Host]. +2023-11-03 16:40:31.018738 [info] create_routing_root: Routing root @ /tmp/vsomeip-0 +2023-11-03 16:40:31.019573 [info] Application(hello_world_service, 4444) is initialized (11, 100). +2023-11-03 16:40:31.020057 [info] Starting vsomeip application "hello_world_service" (4444) using 2 threads I/O nice 255 +2023-11-03 16:40:31.021469 [info] Client [4444] routes unicast:127.19.85.76, netmask:255.255.255.0 +2023-11-03 16:40:31.021484 [info] main dispatch thread id from application: 4444 (hello_world_service) is: 7fbddd0a8640 TID: 311976 +2023-11-03 16:40:31.032740 [info] Watchdog is disabled! +2023-11-03 16:40:31.022487 [info] shutdown thread id from application: 4444 (hello_world_service) is: 7fbddc8a7640 TID: 311977 +2023-11-03 16:40:31.035423 [info] io thread id from application: 4444 (hello_world_service) is: 7fbdde144b80 TID: 311973 +2023-11-03 16:40:31.036405 [info] vSomeIP 3.4.9.1 | (default) +2023-11-03 16:40:31.036308 [info] io thread id from application: 4444 (hello_world_service) is: 7fbdd77fe640 TID: 311979 +2023-11-03 16:40:31.036751 [info] create_local_server: Listening @ /tmp/vsomeip-4444 +2023-11-03 16:40:31.042149 [info] OFFER(4444): [1111.2222:0.0] (true) +2023-11-03 16:40:37.347127 [info] Application/Client 5555 is registering. +2023-11-03 16:40:37.350053 [info] Client [4444] is connecting to [5555] at /tmp/vsomeip-55552023-11-03 16:40:37.360259 [info] REGISTERED_ACK(5555) +2023-11-03 16:40:37.472179 [info] REQUEST(5555): [1111.2222:255.4294967295] +2023-11-03 16:40:37.494451 [info] RELEASE(5555): [1111.2222] +2023-11-03 16:40:37.497856 [info] Application/Client 5555 is deregistering. +2023-11-03 16:40:37.520884 [info] local_uds_client_endpoint_impl::receive_cbk Error: End of file +2023-11-03 16:40:37.611315 [info] Client [4444] is closing connection to [5555] +2023-11-03 16:40:41.330493 [info] vSomeIP 3.4.9.1 | (default) +2023-11-03 16:40:42.493762 [info] STOP OFFER(4444): [1111.2222:0.0] (true) + +Expected output client +---------------------- +2023-11-03 16:40:37.296486 [info] Using configuration file: "../helloworld-local.json". +2023-11-03 16:40:37.335551 [info] Parsed vsomeip configuration in 15ms +2023-11-03 16:40:37.336035 [info] Configuration module loaded. +2023-11-03 16:40:37.336107 [info] Security disabled! +2023-11-03 16:40:37.336144 [info] Initializing vsomeip (3.4.9.1) application "hello_world_client". +2023-11-03 16:40:37.336196 [info] Instantiating routing manager [Proxy]. +2023-11-03 16:40:37.337152 [info] Client [5555] is connecting to [0] at /tmp/vsomeip-0 +2023-11-03 16:40:37.337453 [info] Application(hello_world_client, 5555) is initialized (11, 100). +2023-11-03 16:40:37.337666 [info] Starting vsomeip application "hello_world_client" (5555) using 2 threads I/O nice 255 +2023-11-03 16:40:37.338859 [info] main dispatch thread id from application: 5555 (hello_world_client) is: 7f1ff8197640 TID: 311983 +2023-11-03 16:40:37.339940 [info] shutdown thread id from application: 5555 (hello_world_client) is: 7f1ff7996640 TID: 311984 +2023-11-03 16:40:37.341120 [info] io thread id from application: 5555 (hello_world_client) is: 7f1ff8231b80 TID: 311982 +2023-11-03 16:40:37.341294 [info] io thread id from application: 5555 (hello_world_client) is: 7f1ff7195640 TID: 311985 +2023-11-03 16:40:37.343816 [info] create_local_server: Listening @ /tmp/vsomeip-5555 +2023-11-03 16:40:37.345038 [info] Client 5555 (hello_world_client) successfully connected to routing ~> registering.. +2023-11-03 16:40:37.345108 [info] Registering to routing manager @ vsomeip-0 +2023-11-03 16:40:37.358100 [info] Application/Client 5555 (hello_world_client) is registered. +2023-11-03 16:40:37.477528 [info] ON_AVAILABLE(5555): [1111.2222:0.0] +Sending: World +2023-11-03 16:40:37.478826 [info] Client [5555] is connecting to [4444] at /tmp/vsomeip-4444 +Received: Hello World +2023-11-03 16:40:37.490189 [info] Stopping vsomeip application "hello_world_client" (5555). +2023-11-03 16:40:37.503150 [info] Application/Client 5555 (hello_world_client) is deregistered. +2023-11-03 16:40:37.508752 [info] Client [5555] is closing connection to [4444] +2023-11-03 16:40:37.508823 [info] local_uds_client_endpoint_impl::receive_cbk Error: Operation canceled +2023-11-03 16:40:37.508915 [info] local_uds_client_endpoint_impl::receive_cbk Error: Operation canceled diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme_android b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme_android new file mode 100644 index 00000000000..26ae73ea77b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/hello_world/readme_android @@ -0,0 +1,22 @@ +AOSP: +1. Apply vsomeip project to AOSP tree and build hello_world example (e.g. via mma build command) +2. Push changes to target +3. Start service and client via different adb shell sessions under root user: + +Shell1: +VSOMEIP_CONFIGURATION=/vendor/etc/vsomeip/helloworld-local.json \ +VSOMEIP_APPLICATION_NAME=hello_world_service \ +vsomeip_hello_world_service + +Shell2: +VSOMEIP_CONFIGURATION=/vendor/etc/vsomeip/helloworld-local.json \ +VSOMEIP_APPLICATION_NAME=hello_world_client \ +vsomeip_hello_world_client + +NDK: +AndroidStudio example how to use vsomeip like communication mechanism between two Android services: +https://github.com/nkh-lab/ndk-vsomeip-hello-world + +Expected Android app Logcat output: +2020-06-05 11:13:06.407 31221-31266/com.example.vsomeiphelloworld I/hello_world_client: Sending: World +2020-06-05 11:13:06.437 31221-31266/com.example.vsomeiphelloworld I/hello_world_client: Received: Hello World diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/notify-sample.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/notify-sample.cpp new file mode 100644 index 00000000000..a9306683b08 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/notify-sample.cpp @@ -0,0 +1,265 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <mutex> + +#include <vsomeip/vsomeip.hpp> + +#include "sample-ids.hpp" + +class service_sample { +public: + service_sample(uint32_t _cycle) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + cycle_(_cycle), + blocked_(false), + running_(true), + is_offered_(false), + offer_thread_(std::bind(&service_sample::run, this)), + notify_thread_(std::bind(&service_sample::notify, this)) { + } + + bool init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app_->register_state_handler( + std::bind(&service_sample::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + SAMPLE_SERVICE_ID, + SAMPLE_INSTANCE_ID, + SAMPLE_GET_METHOD_ID, + std::bind(&service_sample::on_get, this, + std::placeholders::_1)); + + app_->register_message_handler( + SAMPLE_SERVICE_ID, + SAMPLE_INSTANCE_ID, + SAMPLE_SET_METHOD_ID, + std::bind(&service_sample::on_set, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_groups; + its_groups.insert(SAMPLE_EVENTGROUP_ID); + app_->offer_event( + SAMPLE_SERVICE_ID, + SAMPLE_INSTANCE_ID, + SAMPLE_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN); + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + payload_ = vsomeip::runtime::get()->create_payload(); + } + + blocked_ = true; + condition_.notify_one(); + return true; + } + + void start() { + app_->start(); + } + + void stop() { + running_ = false; + blocked_ = true; + condition_.notify_one(); + notify_condition_.notify_one(); + app_->clear_all_handler(); + stop_offer(); + if (std::this_thread::get_id() != offer_thread_.get_id()) { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + } else { + offer_thread_.detach(); + } + if (std::this_thread::get_id() != notify_thread_.get_id()) { + if (notify_thread_.joinable()) { + notify_thread_.join(); + } + } else { + notify_thread_.detach(); + } + app_->stop(); + } + + void offer() { + std::lock_guard<std::mutex> its_lock(notify_mutex_); + app_->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + is_offered_ = true; + notify_condition_.notify_one(); + } + + void stop_offer() { + app_->stop_offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + is_offered_ = false; + } + + void on_state(vsomeip::state_type_e _state) { + std::cout << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered.") << std::endl; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + } + } else { + is_registered_ = false; + } + } + + void on_get(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + its_response->set_payload(payload_); + } + app_->send(its_response); + } + + void on_set(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + payload_ = _message->get_payload(); + its_response->set_payload(payload_); + } + + app_->send(its_response); + app_->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, + SAMPLE_EVENT_ID, payload_); + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + bool is_offer(true); + while (running_) { + if (is_offer) + offer(); + else + stop_offer(); + + for (int i = 0; i < 10 && running_; i++) + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + is_offer = !is_offer; + } + } + + void notify() { + + vsomeip::byte_t its_data[10]; + uint32_t its_size = 1; + + while (running_) { + std::unique_lock<std::mutex> its_lock(notify_mutex_); + while (!is_offered_ && running_) + notify_condition_.wait(its_lock); + while (is_offered_ && running_) { + if (its_size == sizeof(its_data)) + its_size = 1; + + for (uint32_t i = 0; i < its_size; ++i) + its_data[i] = static_cast<uint8_t>(i); + + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + payload_->set_data(its_data, its_size); + + std::cout << "Setting event (Length=" << std::dec << its_size << ")." << std::endl; + app_->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, payload_); + } + + its_size++; + + std::this_thread::sleep_for(std::chrono::milliseconds(cycle_)); + } + } + } + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + uint32_t cycle_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool running_; + + std::mutex notify_mutex_; + std::condition_variable notify_condition_; + bool is_offered_; + + std::mutex payload_mutex_; + std::shared_ptr<vsomeip::payload> payload_; + + // blocked_ / is_offered_ must be initialized before starting the threads! + std::thread offer_thread_; + std::thread notify_thread_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + service_sample *its_sample_ptr(nullptr); + void handle_signal(int _signal) { + if (its_sample_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_sample_ptr->stop(); + } +#endif + +int main(int argc, char **argv) { + uint32_t cycle = 1000; // default 1s + + std::string cycle_arg("--cycle"); + + for (int i = 1; i < argc; i++) { + if (cycle_arg == argv[i] && i + 1 < argc) { + i++; + std::stringstream converter; + converter << argv[i]; + converter >> cycle; + } + } + + service_sample its_sample(cycle); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample_ptr = &its_sample; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_sample.init()) { + its_sample.start(); +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample.stop(); +#endif + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/readme.txt b/lib/libsomeip-c/vsomeip-3.5.1/examples/readme.txt new file mode 100644 index 00000000000..219df9bd039 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/readme.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +To use the example applications you need two devices on the same network. The network addresses within +the configuration files need to be adapted to match the devices addresses. + +To start the request/response-example from the build-directory do: + +HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample +HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample + +To start the subscribe/notify-example from the build-directory do: + +HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./subscribe-sample +HOST1: env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./notify-sample diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/request-sample.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/request-sample.cpp new file mode 100644 index 00000000000..dfebe6fb70a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/request-sample.cpp @@ -0,0 +1,242 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> + +#include <vsomeip/vsomeip.hpp> + +#include "sample-ids.hpp" + +class client_sample { +public: + client_sample(bool _use_tcp, bool _be_quiet, uint32_t _cycle) + : app_(vsomeip::runtime::get()->create_application()), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + use_tcp_(_use_tcp), + be_quiet_(_be_quiet), + cycle_(_cycle), + running_(true), + blocked_(false), + is_available_(false), + sender_(std::bind(&client_sample::run, this)) { + } + + bool init() { + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + std::cout << "Client settings [protocol=" + << (use_tcp_ ? "TCP" : "UDP") + << ":quiet=" + << (be_quiet_ ? "true" : "false") + << ":cycle=" + << cycle_ + << "]" + << std::endl; + + app_->register_state_handler( + std::bind( + &client_sample::on_state, + this, + std::placeholders::_1)); + + app_->register_message_handler( + vsomeip::ANY_SERVICE, SAMPLE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&client_sample::on_message, + this, + std::placeholders::_1)); + + request_->set_service(SAMPLE_SERVICE_ID); + request_->set_instance(SAMPLE_INSTANCE_ID); + request_->set_method(SAMPLE_METHOD_ID); + + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector< vsomeip::byte_t > its_payload_data; + for (std::size_t i = 0; i < 10; ++i) + its_payload_data.push_back(vsomeip::byte_t(i % 256)); + its_payload->set_data(its_payload_data); + request_->set_payload(its_payload); + + app_->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, + std::bind(&client_sample::on_availability, + this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + app_->register_availability_handler(SAMPLE_SERVICE_ID + 1, SAMPLE_INSTANCE_ID, + std::bind(&client_sample::on_availability, + this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + return true; + } + + void start() { + app_->start(); + } + + void stop() { + running_ = false; + blocked_ = true; + app_->clear_all_handler(); + app_->release_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + condition_.notify_one(); + if (std::this_thread::get_id() != sender_.get_id()) { + if (sender_.joinable()) { + sender_.join(); + } + } else { + sender_.detach(); + } + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + + if (SAMPLE_SERVICE_ID == _service && SAMPLE_INSTANCE_ID == _instance) { + if (is_available_ && !_is_available) { + is_available_ = false; + } else if (_is_available && !is_available_) { + is_available_ = true; + send(); + } + } + } + + void on_message(const std::shared_ptr< vsomeip::message > &_response) { + std::cout << "Received a response from Service [" + << std::setfill('0') << std::hex + << std::setw(4) << _response->get_service() + << "." + << std::setw(4) << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << _response->get_client() + << "/" + << std::setw(4) << _response->get_session() + << "]" + << std::endl; + if (is_available_) + send(); + } + + void send() { + if (!be_quiet_) + { + std::lock_guard< std::mutex > its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + } + + void run() { + while (running_) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) condition_.wait(its_lock); + if (is_available_) { + app_->send(request_); + std::cout << "Client/Session [" + << std::setfill('0') << std::hex + << std::setw(4) << request_->get_client() + << "/" + << std::setw(4) << request_->get_session() + << "] sent a request to Service [" + << std::setw(4) << request_->get_service() + << "." + << std::setw(4) << request_->get_instance() + << "]" + << std::endl; + blocked_ = false; + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(cycle_)); + } + } + +private: + std::shared_ptr< vsomeip::application > app_; + std::shared_ptr< vsomeip::message > request_; + bool use_tcp_; + bool be_quiet_; + uint32_t cycle_; + std::mutex mutex_; + std::condition_variable condition_; + bool running_; + bool blocked_; + bool is_available_; + + std::thread sender_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + client_sample *its_sample_ptr(nullptr); + void handle_signal(int _signal) { + if (its_sample_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_sample_ptr->stop(); + } +#endif + +int main(int argc, char **argv) { + bool use_tcp = false; + bool be_quiet = false; + uint32_t cycle = 1000; // Default: 1s + + std::string tcp_enable("--tcp"); + std::string udp_enable("--udp"); + std::string quiet_enable("--quiet"); + std::string cycle_arg("--cycle"); + + int i = 1; + while (i < argc) { + if (tcp_enable == argv[i]) { + use_tcp = true; + } else if (udp_enable == argv[i]) { + use_tcp = false; + } else if (quiet_enable == argv[i]) { + be_quiet = true; + } else if (cycle_arg == argv[i] && i+1 < argc) { + i++; + std::stringstream converter; + converter << argv[i]; + converter >> cycle; + } + i++; + } + + client_sample its_sample(use_tcp, be_quiet, cycle); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample_ptr = &its_sample; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_sample.init()) { + its_sample.start(); +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample.stop(); +#endif + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/response-sample.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/response-sample.cpp new file mode 100644 index 00000000000..35b45b74b32 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/response-sample.cpp @@ -0,0 +1,191 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> + +#include <vsomeip/vsomeip.hpp> + +#include "sample-ids.hpp" + +class service_sample { +public: + service_sample(bool _use_static_routing) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + use_static_routing_(_use_static_routing), + blocked_(false), + running_(true), + offer_thread_(std::bind(&service_sample::run, this)) { + } + + bool init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app_->register_state_handler( + std::bind(&service_sample::on_state, this, + std::placeholders::_1)); + app_->register_message_handler( + SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, + std::bind(&service_sample::on_message, this, + std::placeholders::_1)); + + std::cout << "Static routing " << (use_static_routing_ ? "ON" : "OFF") + << std::endl; + return true; + } + + void start() { + app_->start(); + } + + void stop() { + running_ = false; + blocked_ = true; + app_->clear_all_handler(); + stop_offer(); + condition_.notify_one(); + if (std::this_thread::get_id() != offer_thread_.get_id()) { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + } else { + offer_thread_.detach(); + } + app_->stop(); + } + + void offer() { + app_->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + app_->offer_service(SAMPLE_SERVICE_ID + 1, SAMPLE_INSTANCE_ID); + } + + void stop_offer() { + app_->stop_offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + app_->stop_offer_service(SAMPLE_SERVICE_ID + 1, SAMPLE_INSTANCE_ID); + } + + void on_state(vsomeip::state_type_e _state) { + std::cout << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered.") + << std::endl; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + blocked_ = true; + condition_.notify_one(); + } + } else { + is_registered_ = false; + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_request) { + std::cout << "Received a message with Client/Session [" + << std::setfill('0') << std::hex + << std::setw(4) << _request->get_client() << "/" + << std::setw(4) << _request->get_session() << "]" + << std::endl; + + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_request); + + std::shared_ptr<vsomeip::payload> its_payload + = vsomeip::runtime::get()->create_payload(); + std::vector<vsomeip::byte_t> its_payload_data; + for (std::size_t i = 0; i < 120; ++i) + its_payload_data.push_back(vsomeip::byte_t(i % 256)); + its_payload->set_data(its_payload_data); + its_response->set_payload(its_payload); + + app_->send(its_response); + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + bool is_offer(true); + + if (use_static_routing_) { + offer(); + while (running_); + } else { + while (running_) { + if (is_offer) + offer(); + else + stop_offer(); + + for (int i = 0; i < 10 && running_; i++) + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + is_offer = !is_offer; + } + } + } + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + bool use_static_routing_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool running_; + + // blocked_ must be initialized before the thread is started. + std::thread offer_thread_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + service_sample *its_sample_ptr(nullptr); + void handle_signal(int _signal) { + if (its_sample_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_sample_ptr->stop(); + } +#endif + +int main(int argc, char **argv) { + bool use_static_routing(false); + + std::string static_routing_enable("--static-routing"); + + for (int i = 1; i < argc; i++) { + if (static_routing_enable == argv[i]) { + use_static_routing = true; + } + } + + service_sample its_sample(use_static_routing); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample_ptr = &its_sample; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_sample.init()) { + its_sample.start(); +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample.stop(); +#endif + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/CMakeLists.txt new file mode 100644 index 00000000000..e8a2397fc40 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Daemon +add_executable(routingmanagerd routingmanagerd.cpp) +target_link_libraries(routingmanagerd ${VSOMEIP_NAME} ${Boost_LIBRARIES} ${DL_LIBRARY} ${DLT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +if(${CMAKE_SYSTEM_NAME} MATCHES "QNX") + target_link_libraries(routingmanagerd socket) +endif() +add_dependencies(routingmanagerd ${VSOMEIP_NAME}) + +option(VSOMEIP_INSTALL_ROUTINGMANAGERD "Whether or not to install the routing manager daemon.") + +if (VSOMEIP_INSTALL_ROUTINGMANAGERD) + install ( + TARGETS routingmanagerd + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin + ) +endif() + + + +################################################################################################### diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/routingmanagerd.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/routingmanagerd.cpp new file mode 100644 index 00000000000..985dece0048 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/routingmanagerd/routingmanagerd.cpp @@ -0,0 +1,208 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <unistd.h> +#include <thread> +#include <condition_variable> +#include <mutex> +#include <iostream> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef USE_DLT +#ifndef ANDROID +#include <dlt/dlt.h> +#endif +#endif + +static std::shared_ptr<vsomeip::application> its_application; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +static vsomeip::routing_state_e routing_state = vsomeip::routing_state_e::RS_RUNNING; +static bool stop_application = false; +static bool stop_sighandler = false; +static std::condition_variable_any sighandler_condition; +static std::recursive_mutex sighandler_mutex; +#endif + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +/* + * Handle signal to stop the daemon + */ +void routingmanagerd_stop(int _signal) { + // Do not log messages in signal handler as this can cause deadlock in boost logger + switch (_signal) { + case SIGINT: + case SIGTERM: + stop_application = true; + break; + + case SIGUSR1: + routing_state = vsomeip::routing_state_e::RS_SUSPENDED; + break; + + case SIGUSR2: + routing_state = vsomeip::routing_state_e::RS_RESUMED; + break; + + default: + ; + }; + + std::unique_lock<std::recursive_mutex> its_lock(sighandler_mutex); + sighandler_condition.notify_one(); +} +#endif + +/* + * Create a vsomeip application object and start it. + */ +int routingmanagerd_process(bool _is_quiet) { +#ifdef USE_DLT +#ifndef ANDROID + if (!_is_quiet) + DLT_REGISTER_APP(VSOMEIP_LOG_DEFAULT_APPLICATION_ID, VSOMEIP_LOG_DEFAULT_APPLICATION_NAME); +#endif +#else + (void)_is_quiet; +#endif + + std::shared_ptr<vsomeip::runtime> its_runtime + = vsomeip::runtime::get(); + + if (!its_runtime) { + return -1; + } + + // Create the application object + its_application = its_runtime->create_application("routingmanagerd"); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + std::thread sighandler_thread([]() { + // Unblock signals for this thread only + sigset_t handler_mask; + sigemptyset(&handler_mask); + sigaddset(&handler_mask, SIGUSR1); + sigaddset(&handler_mask, SIGUSR2); + sigaddset(&handler_mask, SIGTERM); + sigaddset(&handler_mask, SIGINT); + sigaddset(&handler_mask, SIGSEGV); + sigaddset(&handler_mask, SIGABRT); + pthread_sigmask(SIG_UNBLOCK, &handler_mask, NULL); + + // Handle the following signals + signal(SIGINT, routingmanagerd_stop); + signal(SIGTERM, routingmanagerd_stop); + signal(SIGUSR1, routingmanagerd_stop); + signal(SIGUSR2, routingmanagerd_stop); + + while (!stop_sighandler) { + std::unique_lock<std::recursive_mutex> its_lock(sighandler_mutex); + sighandler_condition.wait(its_lock); + if (stop_application) { + its_application->stop(); + return; + } else if (routing_state == vsomeip::routing_state_e::RS_RESUMED || + routing_state == vsomeip::routing_state_e::RS_SUSPENDED){ + VSOMEIP_INFO << "Received signal for setting routing_state to: 0x" + << std::hex << static_cast<int>(routing_state ); + its_application->set_routing_state(routing_state); + } + } + }); +#endif + if (its_application->init()) { + if (its_application->is_routing()) { + its_application->start(); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + if (std::this_thread::get_id() != sighandler_thread.get_id()) { + if (sighandler_thread.joinable()) { + sighandler_thread.join(); + } + } else { + sighandler_thread.detach(); + } +#endif + return 0; + } + VSOMEIP_ERROR << "routingmanagerd has not been configured as routing - abort"; + } +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + { + std::unique_lock<std::recursive_mutex> its_lock(sighandler_mutex); + stop_sighandler = true; + sighandler_condition.notify_one(); + } + if (std::this_thread::get_id() != sighandler_thread.get_id()) { + if (sighandler_thread.joinable()) { + sighandler_thread.join(); + } + } else { + sighandler_thread.detach(); + } +#endif + return -1; +} + +/* + * Parse command line options + * -h | --help print usage information + * -d | --daemonize start background processing by forking the process + * -q | --quiet do _not_ use dlt logging + * + * and start processing. + */ +int main(int argc, char **argv) { +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + // Block all signals + sigset_t mask; + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, NULL); +#endif + bool must_daemonize(false); + bool is_quiet(false); + if (argc > 1) { + for (int i = 0; i < argc; i++) { + std::string its_argument(argv[i]); + if (its_argument == "-d" || its_argument == "--daemonize") { + must_daemonize = true; + } else if (its_argument == "-q" || its_argument == "--quiet") { + is_quiet = true; + } else if (its_argument == "-h" || its_argument == "--help") { + std::cout << "usage: " + << argv[0] << " [-h|--help][-d|--daemonize][-q|--quiet]" + << std::endl; + return 0; + } + } + } + + /* Fork the process if processing shall be done in the background */ + if (must_daemonize) { + pid_t its_process, its_signature; + + its_process = fork(); + + if (its_process < 0) { + return EXIT_FAILURE; + } + + if (its_process > 0) { + return EXIT_SUCCESS; + } + + umask(0111); + + its_signature = setsid(); + if (its_signature < 0) { + return EXIT_FAILURE; + } + } + + return routingmanagerd_process(is_quiet); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/sample-ids.hpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/sample-ids.hpp new file mode 100644 index 00000000000..6d3113191b2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/sample-ids.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP +#define VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP + +#define SAMPLE_SERVICE_ID 0x1234 +#define SAMPLE_INSTANCE_ID 0x5678 +#define SAMPLE_METHOD_ID 0x0421 + +#define SAMPLE_EVENT_ID 0x8778 +#define SAMPLE_GET_METHOD_ID 0x0001 +#define SAMPLE_SET_METHOD_ID 0x0002 + +#define SAMPLE_EVENTGROUP_ID 0x4465 + +#define OTHER_SAMPLE_SERVICE_ID 0x0248 +#define OTHER_SAMPLE_INSTANCE_ID 0x5422 +#define OTHER_SAMPLE_METHOD_ID 0x1421 + +#endif // VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/examples/subscribe-sample.cpp b/lib/libsomeip-c/vsomeip-3.5.1/examples/subscribe-sample.cpp new file mode 100644 index 00000000000..11f0e1489e9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/examples/subscribe-sample.cpp @@ -0,0 +1,183 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> + +#include <vsomeip/vsomeip.hpp> + +#include "sample-ids.hpp" + +class client_sample { +public: + client_sample(bool _use_tcp) : + app_(vsomeip::runtime::get()->create_application()), use_tcp_( + _use_tcp) { + } + + bool init() { + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + std::cout << "Client settings [protocol=" + << (use_tcp_ ? "TCP" : "UDP") + << "]" + << std::endl; + + app_->register_state_handler( + std::bind(&client_sample::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + vsomeip::ANY_SERVICE, SAMPLE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&client_sample::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, + std::bind(&client_sample::on_availability, + this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + std::set<vsomeip::eventgroup_t> its_groups; + its_groups.insert(SAMPLE_EVENTGROUP_ID); + app_->request_event( + SAMPLE_SERVICE_ID, + SAMPLE_INSTANCE_ID, + SAMPLE_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + app_->subscribe(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENTGROUP_ID); + + return true; + } + + void start() { + app_->start(); + } + + void stop() { + app_->clear_all_handler(); + app_->unsubscribe(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENTGROUP_ID); + app_->release_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID); + app_->release_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + } + + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + std::stringstream its_message; + its_message << "Received a notification for Event [" + << std::setfill('0') << std::hex + << std::setw(4) << _response->get_service() << "." + << std::setw(4) << _response->get_instance() << "." + << std::setw(4) << _response->get_method() << "] to Client/Session [" + << std::setw(4) << _response->get_client() << "/" + << std::setw(4) << _response->get_session() + << "] = "; + std::shared_ptr<vsomeip::payload> its_payload = + _response->get_payload(); + its_message << "(" << std::dec << its_payload->get_length() << ") " + << std::hex << std::setw(2); + for (uint32_t i = 0; i < its_payload->get_length(); ++i) + its_message << std::setw(2) << (int) its_payload->get_data()[i] << " "; + std::cout << its_message.str() << std::endl; + + if (_response->get_client() == 0) { + if ((its_payload->get_length() % 5) == 0) { + std::shared_ptr<vsomeip::message> its_get + = vsomeip::runtime::get()->create_request(); + its_get->set_service(SAMPLE_SERVICE_ID); + its_get->set_instance(SAMPLE_INSTANCE_ID); + its_get->set_method(SAMPLE_GET_METHOD_ID); + its_get->set_reliable(use_tcp_); + app_->send(its_get); + } + + if ((its_payload->get_length() % 8) == 0) { + std::shared_ptr<vsomeip::message> its_set + = vsomeip::runtime::get()->create_request(); + its_set->set_service(SAMPLE_SERVICE_ID); + its_set->set_instance(SAMPLE_INSTANCE_ID); + its_set->set_method(SAMPLE_SET_METHOD_ID); + its_set->set_reliable(use_tcp_); + + const vsomeip::byte_t its_data[] + = { 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x50, 0x51, 0x52 }; + std::shared_ptr<vsomeip::payload> its_set_payload + = vsomeip::runtime::get()->create_payload(); + its_set_payload->set_data(its_data, sizeof(its_data)); + its_set->set_payload(its_set_payload); + app_->send(its_set); + } + } + } + +private: + std::shared_ptr< vsomeip::application > app_; + bool use_tcp_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + client_sample *its_sample_ptr(nullptr); + void handle_signal(int _signal) { + if (its_sample_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_sample_ptr->stop(); + } +#endif + +int main(int argc, char **argv) { + bool use_tcp = false; + + std::string tcp_enable("--tcp"); + std::string udp_enable("--udp"); + + int i = 1; + while (i < argc) { + if (tcp_enable == argv[i]) { + use_tcp = true; + } else if (udp_enable == argv[i]) { + use_tcp = false; + } + i++; + } + + client_sample its_sample(use_tcp); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample_ptr = &its_sample; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_sample.init()) { + its_sample.start(); +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_sample.stop(); +#endif + return 0; + } else { + return 1; + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/exportmap.gcc b/lib/libsomeip-c/vsomeip-3.5.1/exportmap.gcc new file mode 100644 index 00000000000..baedd348c17 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/exportmap.gcc @@ -0,0 +1,71 @@ +{ +global: + extern "C++" { + *vsomeip_v3::configuration; + vsomeip_v3::configuration::*; + *vsomeip_v3::cfg::configuration_impl; + vsomeip_v3::cfg::configuration_impl::*; + *vsomeip_v3::serializer; + vsomeip_v3::serializer::*; + *vsomeip_v3::deserializer; + vsomeip_v3::deserializer::*; + *vsomeip_v3::e2e::e2e_provider_impl; + vsomeip_v3::e2e::e2e_provider_impl::*; + *vsomeip_v3::endpoint_definition; + vsomeip_v3::endpoint_definition*; + *vsomeip_v3::tcp*; + vsomeip_v3::tcp*; + *vsomeip_v3::udp*; + vsomeip_v3::udp*; + *vsomeip_v3::message_base_impl; + *vsomeip_v3::message_base_impl::*; + *vsomeip_v3::message_header_impl; + *vsomeip_v3::message_header_impl::*; + *vsomeip_v3::payload_impl; + *vsomeip_v3::payload_impl::*; + *vsomeip_v3::policy; + vsomeip_v3::policy::*; + *vsomeip_v3::policy_manager; + vsomeip_v3::policy_manager::*; + *vsomeip_v3::policy_manager_impl; + vsomeip_v3::policy_manager_impl::*; + *vsomeip_v3::routing_manager_impl; + vsomeip_v3::routing_manager_impl::*; + vsomeip_v3::security::*; + *vsomeip_v3::runtime; + vsomeip_v3::runtime::get*; + vsomeip_v3::runtime::set_property*; + *vsomeip_v3::application_impl; + vsomeip_v3::application_impl*; + *vsomeip_v3::event; + vsomeip_v3::event::*; + *vsomeip_v3::eventgroupinfo; + vsomeip_v3::eventgroupinfo::*; + *vsomeip_v3::remote_subscription; + vsomeip_v3::remote_subscription::*; + *vsomeip_v3::serviceinfo; + vsomeip_v3::serviceinfo::*; + *vsomeip_v3::sd::runtime; + vsomeip_v3::sd::runtime::*; + *vsomeip_v3::utility; + vsomeip_v3::utility::is*; + vsomeip_v3::utility::data*; + vsomeip_v3::utility::re*; + vsomeip_v3::utility::get_*; + vsomeip_v3::utility::exists*; + *vsomeip_v3::plugin_manager; + vsomeip_v3::plugin_manager::*; + vsomeip_v3::tp::tp_reassembler::*; + *vsomeip_v3::logger::message; + vsomeip_v3::logger::message::*; + *vsomeip_v3::logger::logger_impl; + vsomeip_v3::logger::logger_impl::*; + vsomeip::runtime::*; + *vsomeip::runtime; + vsomeip::logger::*; + *vsomeip::logger; + }; + vsomeip_plugin_init; +local: + *; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_base_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_base_impl.hpp new file mode 100644 index 00000000000..633396527d7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_base_impl.hpp @@ -0,0 +1,82 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_COMPAT_MESSAGE_BASE_IMPL_HPP_ +#define VSOMEIP_COMPAT_MESSAGE_BASE_IMPL_HPP_ + +#include <compat/vsomeip/export.hpp> +#include <compat/vsomeip/message.hpp> +#include <vsomeip/message.hpp> + +namespace vsomeip_v3 { +class message_impl; +} // namespace vsomeip_v3 + +namespace vsomeip { + +class message; + +class message_base_impl + : virtual public message_base { + +public: + VSOMEIP_EXPORT message_base_impl(const std::shared_ptr<vsomeip_v3::message> &_impl); + VSOMEIP_EXPORT virtual ~message_base_impl(); + + VSOMEIP_EXPORT message_t get_message() const; + VSOMEIP_EXPORT void set_message(message_t _message); + + VSOMEIP_EXPORT service_t get_service() const; + VSOMEIP_EXPORT void set_service(service_t _service); + + VSOMEIP_EXPORT instance_t get_instance() const; + VSOMEIP_EXPORT void set_instance(instance_t _instance); + + VSOMEIP_EXPORT method_t get_method() const; + VSOMEIP_EXPORT void set_method(method_t _method); + + VSOMEIP_EXPORT length_t get_length() const; + + VSOMEIP_EXPORT request_t get_request() const; + + VSOMEIP_EXPORT client_t get_client() const; + VSOMEIP_EXPORT void set_client(client_t _client); + + VSOMEIP_EXPORT session_t get_session() const; + VSOMEIP_EXPORT void set_session(session_t _session); + + VSOMEIP_EXPORT protocol_version_t get_protocol_version() const; + + VSOMEIP_EXPORT interface_version_t get_interface_version() const; + VSOMEIP_EXPORT void set_interface_version(interface_version_t _interface_version); + + VSOMEIP_EXPORT message_type_e get_message_type() const; + VSOMEIP_EXPORT void set_message_type(message_type_e _type); + + VSOMEIP_EXPORT return_code_e get_return_code() const; + VSOMEIP_EXPORT void set_return_code(return_code_e _code); + + VSOMEIP_EXPORT bool is_reliable() const; + VSOMEIP_EXPORT void set_reliable(bool _is_reliable); + + VSOMEIP_EXPORT virtual bool is_initial() const; + VSOMEIP_EXPORT virtual void set_initial(bool _is_initial); + + //VSOMEIP_EXPORT message * get_owner() const; + //VSOMEIP_EXPORT void set_owner(message *_owner); + + VSOMEIP_EXPORT bool is_valid_crc() const; + VSOMEIP_EXPORT void set_is_valid_crc(bool _is_valid_crc); + + inline std::shared_ptr<vsomeip_v3::message> get_impl() const { return impl_; } + +protected: + //message *owner_; + std::shared_ptr<vsomeip_v3::message> impl_; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_COMPAT_MESSAGE_BASE_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_impl.hpp new file mode 100644 index 00000000000..d773b976333 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/message_impl.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_COMPAT_MESSAGE_IMPL_HPP_ +#define VSOMEIP_COMPAT_MESSAGE_IMPL_HPP_ + +#if _MSC_VER >= 1300 +# pragma warning( disable : 4250 ) +#endif + +#include <compat/vsomeip/message.hpp> +#include "message_base_impl.hpp" + +namespace vsomeip { + +class payload; + +class message_impl + : virtual public message_base_impl, + virtual public message { + +public: + VSOMEIP_EXPORT message_impl(const std::shared_ptr<vsomeip_v3::message> &_impl); + VSOMEIP_EXPORT virtual ~message_impl(); + + VSOMEIP_EXPORT std::shared_ptr< payload > get_payload() const; + VSOMEIP_EXPORT void set_payload(std::shared_ptr< payload > _payload); + + VSOMEIP_EXPORT bool serialize(serializer *_to) const; + VSOMEIP_EXPORT bool deserialize(deserializer *_from); +}; + +} // namespace vsomeip + +#endif // VSOMEIP_COMPAT_MESSAGE_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/payload_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/payload_impl.hpp new file mode 100644 index 00000000000..1e8b4939363 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/include/payload_impl.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_COMPAT_PAYLOAD_IMPL_HPP_ +#define VSOMEIP_COMPAT_PAYLOAD_IMPL_HPP_ + +#include <compat/vsomeip/payload.hpp> +#include <vsomeip/payload.hpp> + +namespace vsomeip { + +class payload_impl + : public payload { + +public: + payload_impl(const std::shared_ptr<vsomeip_v3::payload> &_impl); + ~payload_impl(); + + bool operator ==(const payload &_other); + + byte_t * get_data(); + const byte_t * get_data() const; + + void set_data(const byte_t *_data, length_t _length); + void set_data(const std::vector<byte_t> &_data); + void set_data(std::vector<byte_t> &&_data); + + length_t get_length() const; + void set_capacity(length_t _length); + + bool deserialize(deserializer *_from); + bool serialize(serializer *_to) const; + + // Wraps + inline std::shared_ptr<vsomeip_v3::payload> get_impl() const { return impl_; } + +private: + std::shared_ptr<vsomeip_v3::payload> impl_; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_COMPAT_PAYLOAD_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_base_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_base_impl.cpp new file mode 100644 index 00000000000..3d646ceb15b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_base_impl.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/runtime.hpp> + +#include "../include/message_base_impl.hpp" +#include "../../../message/include/message_impl.hpp" + +namespace vsomeip { + +message_base_impl::message_base_impl( + const std::shared_ptr<vsomeip_v3::message> &_impl) + : impl_(_impl) { +} + +message_base_impl::~message_base_impl() { +} + +message_t +message_base_impl::get_message() const { + return impl_->get_message(); +} + +void +message_base_impl::set_message(message_t _message) { + impl_->set_message(_message); +} + +service_t +message_base_impl::get_service() const { + return impl_->get_service(); +} + +void +message_base_impl::set_service(service_t _service) { + impl_->set_service(_service); +} + +instance_t +message_base_impl::get_instance() const { + return impl_->get_instance(); +} + +void +message_base_impl::set_instance(instance_t _instance) { + impl_->set_instance(_instance); +} + +method_t +message_base_impl::get_method() const { + return impl_->get_method(); +} + +void +message_base_impl::set_method(method_t _method) { + impl_->set_method(_method); +} + +length_t +message_base_impl::get_length() const { + return impl_->get_length(); +} + +request_t +message_base_impl::get_request() const { + return impl_->get_request(); +} + +client_t +message_base_impl::get_client() const { + return impl_->get_client(); +} + +void +message_base_impl::set_client(client_t _client) { + impl_->set_client(_client); +} + +session_t +message_base_impl::get_session() const { + return impl_->get_session(); +} + +void +message_base_impl::set_session(session_t _session) { + impl_->set_session(_session); +} + +protocol_version_t +message_base_impl::get_protocol_version() const { + return impl_->get_protocol_version(); +} + +interface_version_t +message_base_impl::get_interface_version() const { + return impl_->get_interface_version(); +} + +void +message_base_impl::set_interface_version(interface_version_t _interface_version) { + impl_->set_interface_version(_interface_version); +} + +message_type_e +message_base_impl::get_message_type() const { + return static_cast<message_type_e>(impl_->get_message_type()); +} + +void +message_base_impl::set_message_type(message_type_e _type) { + impl_->set_message_type(static_cast<vsomeip_v3::message_type_e>(_type)); +} + +return_code_e +message_base_impl::get_return_code() const { + return static_cast<return_code_e>(impl_->get_return_code()); +} + +void +message_base_impl::set_return_code(return_code_e _code) { + impl_->set_return_code(static_cast<vsomeip_v3::return_code_e>(_code)); +} + +bool +message_base_impl::is_reliable() const { + return impl_->is_reliable(); +} + +void +message_base_impl::set_reliable(bool _is_reliable) { + impl_->set_reliable(_is_reliable); +} + +bool +message_base_impl::is_initial() const { + return impl_->is_initial(); +} + +void +message_base_impl::set_initial(bool _is_initial) { + impl_->set_initial(_is_initial); +} +/* +message * +message_base_impl::get_owner() const { + return owner_; +} + +void +message_base_impl::set_owner(message *_owner) { + owner_ = _owner; +} +*/ +bool +message_base_impl::is_valid_crc() const { + return impl_->is_valid_crc(); +} + +void +message_base_impl::set_is_valid_crc(bool _is_valid_crc) { + impl_->set_check_result(_is_valid_crc == true ? 1 : 0); +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_impl.cpp new file mode 100644 index 00000000000..3cccc79dc68 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/message_impl.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "../include/message_impl.hpp" +#include "../include/payload_impl.hpp" +#ifdef ANDROID +# include "../../../configuration/include/internal_android.hpp" +#else +# include "../../../configuration/include/internal.hpp" +#endif +#include "../../../message/include/message_impl.hpp" + +namespace vsomeip { + +message_impl::message_impl(const std::shared_ptr<vsomeip_v3::message> &_impl) + : message_base_impl(_impl) { +} + +message_impl::~message_impl() { +} + +std::shared_ptr< payload > +message_impl::get_payload() const { + + return std::make_shared<payload_impl>(impl_->get_payload()); +} + +void +message_impl::set_payload(std::shared_ptr< payload > _payload) { + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->set_payload(its_payload->get_impl()); + } else { + impl_->set_payload(nullptr); + } +} + +bool +message_impl::serialize(serializer *_to) const { + + (void)_to; + VSOMEIP_ERROR << "message_impl::" << __func__ + << ": Must not be called from compatibility layer."; + return false; +} + +bool +message_impl::deserialize(deserializer *_from) { + + (void)_from; + VSOMEIP_ERROR << "message_impl::" << __func__ + << ": Must not be called from compatibility layer."; + return false; +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/payload_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/payload_impl.cpp new file mode 100644 index 00000000000..e1233c22318 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/message/src/payload_impl.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/payload_impl.hpp" +#ifdef ANDROID +# include "../../../configuration/include/internal_android.hpp" +#else +# include "../../../configuration/include/internal.hpp" +#endif + +namespace vsomeip { + +payload_impl::payload_impl(const std::shared_ptr<vsomeip_v3::payload> &_impl) + : impl_(_impl) { +} + +payload_impl::~payload_impl() { +} + +bool +payload_impl::operator==(const payload &_other) { + + bool is_equal(true); + try { + const payload_impl &other = dynamic_cast< const payload_impl & >(_other); + is_equal = (*(impl_.get()) == *(other.impl_.get())); + } + catch (...) { + is_equal = false; + } + return is_equal; +} + +byte_t * +payload_impl::get_data() { + + return impl_->get_data(); +} + +const byte_t * +payload_impl::get_data() const { + + return impl_->get_data(); +} + +length_t +payload_impl::get_length() const { + + return impl_->get_length(); +} + +void +payload_impl::set_capacity(length_t _capacity) { + + impl_->set_capacity(_capacity); +} + +void +payload_impl::set_data(const byte_t *_data, const length_t _length) { + + impl_->set_data(_data, _length); +} + +void +payload_impl::set_data(const std::vector< byte_t > &_data) { + + impl_->set_data(_data); +} + +void +payload_impl::set_data(std::vector< byte_t > &&_data) { + + impl_->set_data(_data); +} + +bool +payload_impl::serialize(serializer *_to) const { + + (void)_to; + VSOMEIP_ERROR << "payload_impl::" << __func__ + << ": Must not be called from compatibility layer."; + return false; +} + +bool +payload_impl::deserialize(deserializer *_from) { + + (void)_from; + VSOMEIP_ERROR << "payload_impl::" << __func__ + << ": Must not be called from compatibility layer."; + return false; +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/application_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/application_impl.hpp new file mode 100644 index 00000000000..8c3b4e0d537 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/application_impl.hpp @@ -0,0 +1,202 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_COMPAT_APPLICATION_IMPL_HPP_ +#define VSOMEIP_COMPAT_APPLICATION_IMPL_HPP_ + +#include <map> +#include <mutex> + +#include <compat/vsomeip/application.hpp> + +namespace vsomeip_v3 { +class application; +} // namespace vsomeip_v3 + +namespace vsomeip { + +class application_impl + : public application { +public: + application_impl(const std::string &_name); + ~application_impl(); + + const std::string & get_name() const; + client_t get_client() const; + + void set_configuration( + const std::shared_ptr<configuration> _configuration); + + bool init(); + void start(); + void stop(); + + void offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + void stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void offer_event(service_t _service, instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, bool _is_field); + void stop_offer_event(service_t _service, instance_t _instance, + event_t _event); + + void request_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _use_exclusive_proxy); + void release_service(service_t _service, instance_t _instance); + + void request_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field); + void release_event(service_t _service, instance_t _instance, + event_t _event); + + void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + subscription_type_e _subscription_type, + event_t _event); + void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup); + + bool is_available(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + void send(std::shared_ptr<message> _message, bool _flush); + void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload) const; + void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client) const; + + void register_state_handler(state_handler_t _handler); + void unregister_state_handler(); + + void register_message_handler(service_t _service, + instance_t _instance, method_t _method, + message_handler_t _handler); + void unregister_message_handler(service_t _service, + instance_t _instance, method_t _method); + + void register_availability_handler(service_t _service, + instance_t _instance, availability_handler_t _handler, + major_version_t _major, minor_version_t _minor); + void unregister_availability_handler(service_t _service, + instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + subscription_handler_t _handler); + void unregister_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void register_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + error_handler_t _handler); + void unregister_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + void clear_all_handler(); + + bool is_routing() const; + + void offer_event(service_t _service, + instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, + bool _is_field, + std::chrono::milliseconds _cycle, + bool _change_resets_cycle, + const epsilon_change_func_t &_epsilon_change_func); + + void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force) const; + + void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force) const; + + bool are_available(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force, bool _flush) const; + + void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force, bool _flush) const; + + void set_routing_state(routing_state_e _routing_state); + + void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler); + + void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective); + + void get_offered_services_async( + offer_type_e _offer_type, offered_services_handler_t _handler); + + void set_watchdog_handler( + watchdog_handler_t _handler, std::chrono::seconds _interval); + + virtual void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_t _handler); + + virtual void set_offer_acceptance_required( + ip_address_t _address, const std::string _path, bool _enable); + + virtual offer_acceptance_map_type_t get_offer_acceptance_required(); + + virtual void register_offer_acceptance_handler( + offer_acceptance_handler_t _handler); + + virtual void register_reboot_notification_handler( + reboot_notification_handler_t _handler); + + virtual void register_routing_ready_handler( + routing_ready_handler_t _handler); + + virtual void register_routing_state_handler( + routing_state_handler_t _handler); + + virtual bool update_service_configuration( + service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + bool _magic_cookies_enabled, bool _offer); + + virtual void update_security_policy_configuration( + uint32_t _uid, uint32_t _gid, + std::shared_ptr<policy> _policy, std::shared_ptr<payload> _payload, + security_update_handler_t _handler); + + virtual void remove_security_policy_configuration( + uint32_t _uid, uint32_t _gid, security_update_handler_t _handler); + +private: + bool is_selective_event( + vsomeip::service_t _service, vsomeip::instance_t _instance, + const std::set<vsomeip::eventgroup_t> &_eventgroups); + +private: + std::shared_ptr<vsomeip_v3::application> impl_; + + std::map<service_t, + std::map<instance_t, std::set<eventgroup_t> > > eventgroups_; + std::mutex eventgroups_mutex_; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_COMPAT_APPLICATION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/runtime_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/runtime_impl.hpp new file mode 100644 index 00000000000..caadbfae257 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/include/runtime_impl.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_COMPAT_RUNTIME_IMPL_HPP_ +#define VSOMEIP_COMPAT_RUNTIME_IMPL_HPP_ + +#include <map> +#include <mutex> + +#include <compat/vsomeip/runtime.hpp> + +namespace vsomeip { + +class runtime_impl + : public runtime { +public: + static std::string get_property(const std::string &_name); + static void set_property(const std::string &_name, const std::string &_value); + + static std::shared_ptr<runtime> get(); + + ~runtime_impl(); + + std::shared_ptr<application> create_application( + const std::string &_name = ""); + + std::shared_ptr<message> create_message(bool _reliable = false) const; + + std::shared_ptr<message> create_request(bool _reliable = false) const; + + std::shared_ptr<message> create_response( + const std::shared_ptr<message> &_request) const; + + std::shared_ptr<message> create_notification( + bool _reliable = false) const; + + std::shared_ptr<payload> create_payload() const; + std::shared_ptr<payload> create_payload( + const byte_t *_data, uint32_t _size) const; + virtual std::shared_ptr<payload> create_payload( + const std::vector<byte_t> &_data) const; + + std::shared_ptr<application> get_application( + const std::string &_name) const; + void remove_application( const std::string &_name); + +private: + static std::shared_ptr<runtime> the_runtime_; + + std::map<std::string, std::weak_ptr<application> > applications_; + mutable std::mutex applications_mutex_; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_COMPAT_RUNTIME_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/application_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/application_impl.cpp new file mode 100644 index 00000000000..f1934e446e3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/application_impl.cpp @@ -0,0 +1,654 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/application.hpp> +#include <vsomeip/runtime.hpp> +#include <compat/vsomeip/runtime.hpp> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/application_impl.hpp" +#ifdef ANDROID +# include "../../../configuration/include/internal_android.hpp" +#else +# include "../../../configuration/include/internal.hpp" +#endif +#include "../../message/include/message_impl.hpp" +#include "../../message/include/payload_impl.hpp" + +namespace vsomeip { + +application_impl::application_impl(const std::string &_name) { + + impl_ = vsomeip_v3::runtime::get()->create_application(_name); +} + +application_impl::~application_impl() { + + vsomeip::runtime::get()->remove_application(impl_->get_name()); +} + +const std::string & +application_impl::get_name() const { + + return impl_->get_name(); +} + +client_t +application_impl::get_client() const { + + return impl_->get_client(); +} + +void +application_impl::set_configuration(const std::shared_ptr<configuration> _configuration) { + + (void)_configuration; + // Not implemented +} + +bool +application_impl::init() { + + return impl_->init(); +} + +void +application_impl::start() { + + impl_->start(); +} + +void +application_impl::stop() { + + impl_->stop(); +} + +void +application_impl::offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + impl_->offer_service(_service, _instance, _major, _minor); +} + +void +application_impl::stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + impl_->stop_offer_service(_service, _instance, _major, _minor); +} + +void +application_impl::offer_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field) { + + // Set event type + vsomeip_v3::event_type_e its_type(vsomeip_v3::event_type_e::ET_EVENT); + if (_is_field) + its_type = vsomeip_v3::event_type_e::ET_FIELD; + else { + // Find out whether the event is selective. Requires a preceding + // call to "register_subscription_handler". + // Note: The check can be done on the eventgroup(s) as selective + // events own an exclusive eventgroup. + const bool is_selective + = is_selective_event(_service, _instance, _eventgroups); + + if (is_selective) + its_type = vsomeip_v3::event_type_e::ET_SELECTIVE_EVENT; + } + + impl_->offer_event(_service, _instance, _event, _eventgroups, its_type); +} + +void +application_impl::stop_offer_event(service_t _service, instance_t _instance, + event_t _event) { + + impl_->stop_offer_event(_service, _instance, _event); +} + +void +application_impl::request_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _use_exclusive_proxy) { + + (void)_use_exclusive_proxy; + impl_->request_service(_service, _instance, _major, _minor); +} + +void +application_impl::release_service(service_t _service, instance_t _instance) { + + impl_->release_service(_service, _instance); +} + +void +application_impl::request_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field) { + + const vsomeip_v3::event_type_e its_type = (_is_field) ? + vsomeip_v3::event_type_e::ET_FIELD : + vsomeip_v3::event_type_e::ET_EVENT; + impl_->request_event(_service, _instance, _event, _eventgroups, its_type); +} + +void +application_impl::release_event(service_t _service, instance_t _instance, + event_t _event) { + + impl_->release_event(_service, _instance, _event); +} + +void +application_impl::subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + subscription_type_e _subscription_type, event_t _event) { + + (void)_subscription_type; // unused in v3 + impl_->subscribe(_service, _instance, _eventgroup, _major, _event); +} + +void +application_impl::unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) { + + impl_->unsubscribe(_service, _instance, _eventgroup); +} + +bool +application_impl::is_available(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + + return impl_->is_available(_service, _instance, _major, _minor); +} + +void +application_impl::send(std::shared_ptr<message> _message, bool _flush = true) { + + (void)_flush; // unused in v3 + if (_message) { + auto its_message = std::dynamic_pointer_cast<message_impl>(_message); + impl_->send(its_message->get_impl()); + } +} + +void +application_impl::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload) const { + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify(_service, _instance, _event, its_payload->get_impl()); + } else { + impl_->notify(_service, _instance, _event, nullptr); + } +} + +void +application_impl::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client) const { + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify_one(_service, _instance, _event, its_payload->get_impl(), _client); + } else { + impl_->notify_one(_service, _instance, _event, nullptr, _client); + } +} + +void +application_impl::register_state_handler(state_handler_t _handler) { + + impl_->register_state_handler( + [_handler](vsomeip_v3::state_type_e _state) { + _handler(static_cast<vsomeip::state_type_e>(_state)); + } + ); +} + +void +application_impl::unregister_state_handler() { + + impl_->unregister_state_handler(); +} + +void +application_impl::register_message_handler( + service_t _service, instance_t _instance, method_t _method, + message_handler_t _handler) { + + impl_->register_message_handler(_service, _instance, _method, + [_handler](const std::shared_ptr<vsomeip_v3::message> &_message) { + auto its_message = std::make_shared<message_impl>(_message); + _handler(its_message); + } + ); +} + +void +application_impl::unregister_message_handler( + service_t _service, instance_t _instance, method_t _method) { + + impl_->unregister_message_handler(_service, _instance, _method); +} + +void +application_impl::register_availability_handler( + service_t _service, instance_t _instance, + availability_handler_t _handler, + major_version_t _major, minor_version_t _minor) { + + impl_->register_availability_handler(_service, _instance, _handler, + _major, _minor); +} + +void +application_impl::unregister_availability_handler( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + impl_->unregister_availability_handler(_service, _instance, _major, _minor); +} + +void +application_impl::register_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + subscription_handler_t _handler) { + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + eventgroups_[_service][_instance].insert(_eventgroup); + } + + impl_->register_subscription_handler(_service, _instance, _eventgroup, + [_handler](client_t _client, vsomeip::uid_t _uid, + vsomeip::gid_t _gid, bool _accepted){ + (void)_uid; + (void)_gid; + return _handler(_client, _accepted); + } + ); +} + +void +application_impl::unregister_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + + impl_->unregister_subscription_handler(_service, _instance, _eventgroup); +} + + +// subscription_error_handlers were exclusively used for selective events. +// As selective events use an exclusive eventgroup, the event identifier +// itself is not needed and we can use a dummy. +#define ERROR_HANDLER_DUMMY_EVENT 0xFFFE + +void +application_impl::register_subscription_error_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + error_handler_t _handler) { + + impl_->register_subscription_status_handler( + _service, _instance, _eventgroup, ERROR_HANDLER_DUMMY_EVENT, + [_handler](service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + uint16_t _error) { + (void)_service; + (void)_instance; + (void)_eventgroup; + (void)_event; + + _handler(_error); + }, + true + ); +} + +void +application_impl::unregister_subscription_error_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + + impl_->unregister_subscription_status_handler(_service, _instance, + _eventgroup, ERROR_HANDLER_DUMMY_EVENT); +} + +void +application_impl::clear_all_handler() { + + impl_->clear_all_handler(); +} + +bool +application_impl::is_routing() const { + + return impl_->is_routing(); +} + +void +application_impl::offer_event( + service_t _service, instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, + bool _is_field, + std::chrono::milliseconds _cycle, + bool _change_resets_cycle, + const epsilon_change_func_t &_epsilon_change_func) { + + // Set event type + vsomeip_v3::event_type_e its_type(vsomeip_v3::event_type_e::ET_EVENT); + if (_is_field) + its_type = vsomeip_v3::event_type_e::ET_FIELD; + else { + // Find out whether the event is selective. Requires a preceding + // call to "register_subscription_handler". + // Note: The check can be done on the eventgroup(s) as selective + // events own an exclusive eventgroup. + const bool is_selective + = is_selective_event(_service, _instance, _eventgroups); + + if (is_selective) + its_type = vsomeip_v3::event_type_e::ET_SELECTIVE_EVENT; + } + + impl_->offer_event(_service, _instance, _event, _eventgroups, + its_type, _cycle, _change_resets_cycle, true, + [_epsilon_change_func]( + const std::shared_ptr<vsomeip_v3::payload> &_lhs, + const std::shared_ptr<vsomeip_v3::payload> &_rhs) { + auto its_lhs = std::make_shared<payload_impl>(_lhs); + auto its_rhs = std::make_shared<payload_impl>(_rhs); + return _epsilon_change_func(its_lhs, its_rhs); + } + ); +} + +void +application_impl::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, bool _force) const { + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify(_service, _instance, _event, its_payload->get_impl(), + _force); + } else { + impl_->notify(_service, _instance, _event, nullptr, _force); + } +} + +void +application_impl::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force) const { + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify_one(_service, _instance, _event, its_payload->get_impl(), + _client, _force); + } else { + impl_->notify_one(_service, _instance, _event, nullptr, _client, + _force); + } +} + +bool +application_impl::are_available(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + + return impl_->are_available(_available, _service, _instance, _major, + _minor); +} + +void +application_impl::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force, bool _flush) const { + + (void)_flush; // unused in v3 + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify(_service, _instance, _event, its_payload->get_impl(), + _force); + } else { + impl_->notify(_service, _instance, _event, nullptr, _force); + } +} + +void +application_impl::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force, bool _flush) const { + + (void)_flush; // unused in v3 + + if (_payload) { + auto its_payload = std::dynamic_pointer_cast<payload_impl>(_payload); + impl_->notify_one(_service, _instance, _event, its_payload->get_impl(), + _client, _force); + } else { + impl_->notify_one(_service, _instance, _event, nullptr, _client, + _force); + } +} + +void +application_impl::set_routing_state(routing_state_e _routing_state) { + + impl_->set_routing_state( + static_cast<vsomeip_v3::routing_state_e>(_routing_state)); +} + +void +application_impl::unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + + impl_->unsubscribe(_service, _instance, _eventgroup, _event); +} + +void +application_impl::register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler) { + + register_subscription_status_handler(_service, _instance, + _eventgroup, _event, _handler, false); +} + +void +application_impl::register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective) { + if (_is_selective) { + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(_eventgroup); + // An application may call "register_event" before + // "register_subscription_status_handler". While the call to + // "register_subscription_status_handler" contains the information + // whether an event is selective, the call to "register_event" does + // not. Therefore, we re-register the event with correct event type + // here. + impl_->request_event(_service, _instance, _event, its_eventgroups, + vsomeip_v3::event_type_e::ET_SELECTIVE_EVENT); + } + + impl_->register_subscription_status_handler(_service, _instance, + _eventgroup, _event, + [_handler](const vsomeip_v3::service_t _service, + const vsomeip_v3::instance_t _instance, + const vsomeip_v3::eventgroup_t _eventgroup, + const vsomeip_v3::event_t _event, + const uint16_t _error) { + + if (_handler) + _handler(_service, _instance, _eventgroup, _event, _error); + }, + _is_selective); +} + +void +application_impl::get_offered_services_async( + offer_type_e _offer_type, offered_services_handler_t _handler) { + + impl_->get_offered_services_async( + static_cast<vsomeip_v3::offer_type_e>(_offer_type), _handler); +} + +void +application_impl::set_watchdog_handler( + watchdog_handler_t _handler, std::chrono::seconds _interval) { + + impl_->set_watchdog_handler(_handler, _interval); +} + +void +application_impl::register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_t _handler) { + + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + eventgroups_[_service][_instance].insert(_eventgroup); + } + impl_->register_async_subscription_handler(_service, _instance, + _eventgroup, [_handler](client_t _client, + vsomeip::uid_t _uid, vsomeip::gid_t _gid, bool _accepted, + std::function<void(const bool)> _handler2) { + (void)_uid; + (void)_gid; + _handler(_client, _accepted, _handler2); + }); +} + +//////////////////////////////////////////////////////////////////////////////// +// The following methods are not implemented as they should only be used by +// plugin implementations that are not intended to run in compatibility mode +//////////////////////////////////////////////////////////////////////////////// +void +application_impl::set_offer_acceptance_required( + ip_address_t _address, const std::string _path, bool _enable) { + + (void)_address; + (void)_path; + (void)_enable; + + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +vsomeip::application::offer_acceptance_map_type_t +application_impl::get_offer_acceptance_required() { + + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; + return vsomeip::application::offer_acceptance_map_type_t(); +} + +void +application_impl::register_offer_acceptance_handler( + offer_acceptance_handler_t _handler) { + + (void)_handler; + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +void +application_impl::register_reboot_notification_handler( + reboot_notification_handler_t _handler) { + + (void)_handler; + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +void +application_impl::register_routing_ready_handler( + routing_ready_handler_t _handler) { + + (void)_handler; + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +void +application_impl::register_routing_state_handler( + routing_state_handler_t _handler) { + + (void)_handler; + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +bool +application_impl::update_service_configuration( + service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + bool _magic_cookies_enabled, bool _offer) { + + (void)_service; + (void)_instance; + (void)_port; + (void)_reliable; + (void)_magic_cookies_enabled; + (void)_offer; + + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; + return false; +} + +void +application_impl::update_security_policy_configuration( + uint32_t _uid, uint32_t _gid, + std::shared_ptr<policy> _policy, std::shared_ptr<payload> _payload, + security_update_handler_t _handler) { + + (void)_uid; + (void)_gid; + (void)_policy; + (void)_payload; + (void)_handler; + + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +void +application_impl::remove_security_policy_configuration( + uint32_t _uid, uint32_t _gid, security_update_handler_t _handler) { + + (void)_uid; + (void)_gid; + (void)_handler; + + VSOMEIP_ERROR << __func__ << ": Must not be called from compatibility layer."; +} + +//////////////////////////////////////////////////////////////////////////////// +// Private helper +//////////////////////////////////////////////////////////////////////////////// + +bool +application_impl::is_selective_event( + vsomeip::service_t _service, vsomeip::instance_t _instance, + const std::set<vsomeip::eventgroup_t> &_eventgroups) { + + bool is_selective(false); + + std::lock_guard<std::mutex> its_events_lock(eventgroups_mutex_); + const auto its_service = eventgroups_.find(_service); + if (its_service != eventgroups_.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + for (const auto eg : _eventgroups) { + const auto its_egrp = its_instance->second.find(eg); + if (its_egrp != its_instance->second.end()) { + is_selective = true; + break; + } + } + } + } + + return is_selective; +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime.cpp new file mode 100644 index 00000000000..40075a86385 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <compat/vsomeip/runtime.hpp> +#include "../include/runtime_impl.hpp" + +namespace vsomeip { + +std::string +runtime::get_property(const std::string &_name) { + + return runtime_impl::get_property(_name); +} + +void +runtime::set_property(const std::string &_name, const std::string &_value) { + + runtime_impl::set_property(_name, _value); +} + +std::shared_ptr<runtime> +runtime::get() { + + return runtime_impl::get(); +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime_impl.cpp new file mode 100644 index 00000000000..b155333452e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/compat/runtime/src/runtime_impl.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <compat/vsomeip/defines.hpp> +#include <vsomeip/runtime.hpp> + +#include "../include/application_impl.hpp" +#include "../include/runtime_impl.hpp" +#include "../../message/include/message_impl.hpp" +#include "../../message/include/payload_impl.hpp" + +namespace vsomeip { + +std::shared_ptr<runtime> runtime_impl::the_runtime_ + = std::make_shared<runtime_impl>(); + +std::string +runtime_impl::get_property(const std::string &_name) { + + return vsomeip_v3::runtime::get_property(_name); +} + +void +runtime_impl::set_property(const std::string &_name, const std::string &_value) { + + vsomeip_v3::runtime::set_property(_name, _value); +} + +std::shared_ptr<runtime> +runtime_impl::get() { + + return the_runtime_; +} + +runtime_impl::~runtime_impl() { +} + +std::shared_ptr<application> +runtime_impl::create_application(const std::string &_name) { + std::lock_guard<std::mutex> its_lock(applications_mutex_); + auto its_application = std::make_shared<application_impl>(_name); + applications_[its_application->get_name()] = its_application; + return (its_application); +} + +std::shared_ptr<message> +runtime_impl::create_message(bool _reliable) const { + + auto its_impl = vsomeip_v3::runtime::get()->create_message(_reliable); + return (std::make_shared<message_impl>(its_impl)); +} + +std::shared_ptr<message> +runtime_impl::create_request(bool _reliable) const { + + auto its_impl = vsomeip_v3::runtime::get()->create_request(_reliable); + return (std::make_shared<message_impl>(its_impl)); +} + +std::shared_ptr<message> +runtime_impl::create_response(const std::shared_ptr<message> &_request) const { + + auto its_request = std::dynamic_pointer_cast<message_impl>(_request); + auto its_impl = vsomeip_v3::runtime::get()->create_response( + its_request->get_impl()); + return (std::make_shared<message_impl>(its_impl)); +} + +std::shared_ptr<message> +runtime_impl::create_notification(bool _reliable) const { + + auto its_impl = vsomeip_v3::runtime::get()->create_notification(_reliable); + return (std::make_shared<message_impl>(its_impl)); +} + +std::shared_ptr<payload> +runtime_impl::create_payload() const { + + auto its_impl = vsomeip_v3::runtime::get()->create_payload(); + return (std::make_shared<payload_impl>(its_impl)); +} + +std::shared_ptr<payload> +runtime_impl::create_payload(const byte_t *_data, uint32_t _size) const { + + auto its_impl = vsomeip_v3::runtime::get()->create_payload(_data, _size); + return (std::make_shared<payload_impl>(its_impl)); +} + +std::shared_ptr<payload> +runtime_impl::create_payload(const std::vector<byte_t> &_data) const { + + auto its_impl = vsomeip_v3::runtime::get()->create_payload(_data); + return (std::make_shared<payload_impl>(its_impl)); +} + +std::shared_ptr<application> +runtime_impl::get_application(const std::string &_name) const { + + std::lock_guard<std::mutex> its_lock(applications_mutex_); + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) + return found_application->second.lock(); + + return (nullptr); +} + +void +runtime_impl::remove_application(const std::string &_name) { + + std::lock_guard<std::mutex> its_lock(applications_mutex_); + auto found_application = applications_.find(_name); + if(found_application != applications_.end()) { + applications_.erase(_name); + } +} + +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/application_configuration.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/application_configuration.hpp new file mode 100644 index 00000000000..81ab7aa6a2f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/application_configuration.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_APPLICATION_CONFIGURATION_HPP_ +#define VSOMEIP_V3_CFG_APPLICATION_CONFIGURATION_HPP_ + +#include <map> +#include <set> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/plugin.hpp> + +#include "debounce_filter_impl.hpp" + +namespace vsomeip_v3 { + +namespace cfg { + +struct application_configuration { + client_t client_; + std::size_t max_dispatchers_; + std::size_t max_dispatch_time_; + std::size_t max_detach_thread_wait_time_; + std::size_t thread_count_; + std::size_t request_debouncing_; + std::map<plugin_type_e, std::set<std::string> > plugins_; + int nice_level_; + debounce_configuration_t debounces_; + bool has_session_handling_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_APPLICATION_CONFIGURATION_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/client.hpp new file mode 100644 index 00000000000..5c0805dda2e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/client.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_CLIENT_HPP +#define VSOMEIP_V3_CFG_CLIENT_HPP + +#include <map> +#include <memory> +#include <set> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct client { + client() : service_(ANY_SERVICE), + instance_(ANY_INSTANCE) { + } + + // ports for specific service / instance + service_t service_; + instance_t instance_; + std::map<bool, std::set<uint16_t> > ports_; + std::map<bool, uint16_t> last_used_specific_client_port_; + + // client port ranges mapped to remote port ranges + std::map<bool, std::pair<uint16_t, uint16_t> > remote_ports_; + std::map<bool, std::pair<uint16_t, uint16_t> > client_ports_; + std::map<bool, uint16_t> last_used_client_port_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration.hpp new file mode 100644 index 00000000000..15fbc9c7db7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration.hpp @@ -0,0 +1,322 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CONFIGURATION_HPP +#define VSOMEIP_V3_CONFIGURATION_HPP + +#include <map> +#include <memory> +#include <set> +#include <string> +#include <chrono> + +#include <boost/asio/ip/address.hpp> +#include <boost/icl/interval_set.hpp> + +#include <vsomeip/export.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/plugin.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "trace.hpp" + +#include "../../e2e_protection/include/e2exf/config.hpp" +#include "e2e.hpp" + + +#ifdef ANDROID +#include "internal_android.hpp" +#else +#include "internal.hpp" +#endif // ANDROID + +#include "../../security/include/policy.hpp" + +#define VSOMEIP_CONFIG_PLUGIN_VERSION 1 + +namespace vsomeip_v3 { + +class policy_manager_impl; +class security; +class event; +struct debounce_filter_impl_t; + +class configuration { +public: + virtual ~configuration() +#ifndef ANDROID + {} +#else + ; +#endif + + virtual bool load(const std::string &_name) = 0; +#ifndef VSOMEIP_DISABLE_SECURITY + virtual bool lazy_load_security(const std::string &_client_host) = 0; +#endif // !VSOMEIP_DISABLE_SECURITY + virtual bool remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) = 0; + virtual bool remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote) = 0; + + virtual const std::string &get_network() const = 0; + + virtual const boost::asio::ip::address & get_unicast_address() const = 0; + virtual const boost::asio::ip::address& get_netmask() const = 0; + virtual unsigned short get_prefix() const = 0; + virtual const std::string &get_device() const = 0; + virtual diagnosis_t get_diagnosis_address() const = 0; + virtual diagnosis_t get_diagnosis_mask() const = 0; + virtual bool is_v4() const = 0; + virtual bool is_v6() const = 0; + + virtual bool has_console_log() const = 0; + virtual bool has_file_log() const = 0; + virtual bool has_dlt_log() const = 0; + virtual const std::string &get_logfile() const = 0; + virtual logger::level_e get_loglevel() const = 0; + + virtual bool is_routing_enabled() const = 0; + virtual const std::string &get_routing_host_name() const = 0; + virtual const boost::asio::ip::address &get_routing_host_address() const = 0; + virtual port_t get_routing_host_port() const = 0; + + virtual const boost::asio::ip::address &get_routing_guest_address() const = 0; + virtual std::set<std::pair<port_t, port_t> > get_routing_guest_ports( + uid_t _uid, gid_t _gid) const = 0; + + virtual bool is_local_routing() const = 0; + + virtual std::string get_unicast_address(service_t _service, + instance_t _instance) const = 0; + virtual uint16_t get_reliable_port(service_t _service, + instance_t _instance) const = 0; + virtual bool has_enabled_magic_cookies(const std::string &_address, + uint16_t _port) const = 0; + virtual uint16_t get_unreliable_port(service_t _service, + instance_t _instance) const = 0; + + virtual void get_configured_timing_requests( + service_t _service, const std::string &_ip_target, + std::uint16_t _port_target, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const = 0; + virtual void get_configured_timing_responses( + service_t _service, const std::string &_ip_service, + std::uint16_t _port_service, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const = 0; + + virtual bool is_someip(service_t _service, instance_t _instance) const = 0; + + virtual bool get_client_port(service_t _service, instance_t _instance, + uint16_t _remote_port, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports, uint16_t &_client_port) const = 0; + + virtual std::set<std::pair<service_t, instance_t> > get_remote_services() const = 0; + + virtual bool get_multicast(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const = 0; + + virtual uint8_t get_threshold(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const = 0; + + virtual void get_event_update_properties( + service_t _service, instance_t _instance, event_t _event, + std::chrono::milliseconds &_cycle, + bool &_change_resets_cycle, bool &_update_on_change_) const = 0; + + virtual client_t get_id(const std::string &_name) const = 0; + virtual bool is_configured_client_id(client_t _id) const = 0; + + virtual std::size_t get_max_dispatchers(const std::string &_name) const = 0; + virtual std::size_t get_max_dispatch_time(const std::string &_name) const = 0; + virtual std::size_t get_max_detached_thread_wait_time(const std::string& _name) const = 0; + virtual std::size_t get_io_thread_count(const std::string &_name) const = 0; + virtual int get_io_thread_nice_level(const std::string &_name) const = 0; + virtual std::size_t get_request_debouncing(const std::string &_name) const = 0; + virtual bool has_session_handling(const std::string &_name) const = 0; + + virtual std::uint32_t get_max_message_size_local() const = 0; + virtual std::uint32_t get_max_message_size_reliable(const std::string& _address, + std::uint16_t _port) const = 0; + virtual std::uint32_t get_max_message_size_unreliable() const = 0; + virtual std::uint32_t get_buffer_shrink_threshold() const = 0; + + virtual bool supports_selective_broadcasts(const boost::asio::ip::address &_address) const = 0; + + virtual bool is_offered_remote(service_t _service, instance_t _instance) const = 0; + + virtual bool is_local_service(service_t _service, instance_t _instance) const = 0; + + virtual reliability_type_e get_event_reliability( + service_t _service, instance_t _instance, event_t _event) const = 0; + virtual reliability_type_e get_service_reliability( + service_t _service, instance_t _instance) const = 0; + + // Service Discovery configuration + virtual bool is_sd_enabled() const = 0; + + virtual const std::string & get_sd_multicast() const = 0; + virtual uint16_t get_sd_port() const = 0; + virtual const std::string & get_sd_protocol() const = 0; + + virtual uint32_t get_sd_initial_delay_min() const = 0; + virtual uint32_t get_sd_initial_delay_max() const = 0; + virtual int32_t get_sd_repetitions_base_delay() const = 0; + virtual uint8_t get_sd_repetitions_max() const = 0; + virtual ttl_t get_sd_ttl() const = 0; + virtual int32_t get_sd_cyclic_offer_delay() const = 0; + virtual int32_t get_sd_request_response_delay() const = 0; + virtual std::uint32_t get_sd_offer_debounce_time() const = 0; + virtual std::uint32_t get_sd_find_debounce_time() const = 0; + + // Trace configuration + virtual std::shared_ptr<cfg::trace> get_trace() const = 0; + + // Watchdog + virtual bool is_watchdog_enabled() const = 0; + virtual uint32_t get_watchdog_timeout() const = 0; + virtual uint32_t get_allowed_missing_pongs() const = 0; + + // File permissions + virtual std::uint32_t get_permissions_uds() const = 0; + + virtual bool log_version() const = 0; + virtual uint32_t get_log_version_interval() const = 0; + + // Plugins + virtual std::map<plugin_type_e, std::set<std::string>> get_plugins( + const std::string &_name) const = 0; + + virtual void set_configuration_path(const std::string &_path) = 0; + + virtual std::map<std::string, std::string> get_additional_data( + const std::string &_application_name, + const std::string &_plugin_name) = 0; + + //E2E + virtual std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const = 0; + virtual bool is_e2e_enabled() const = 0; + + virtual bool log_memory() const = 0; + virtual uint32_t get_log_memory_interval() const = 0; + + virtual bool log_status() const = 0; + virtual uint32_t get_log_status_interval() const = 0; + + // TTL factor + typedef std::uint32_t ttl_factor_t; + typedef std::map<service_t, std::map<instance_t, ttl_factor_t>> ttl_map_t; + virtual ttl_map_t get_ttl_factor_offers() const = 0; + virtual ttl_map_t get_ttl_factor_subscribes() const = 0; + + // Debouncing + virtual std::shared_ptr<debounce_filter_impl_t> get_debounce( + const std::string &_name, + service_t _service, instance_t _instance, event_t _event) const = 0; + + // Queue size limit endpoints + typedef std::uint32_t endpoint_queue_limit_t; + virtual endpoint_queue_limit_t get_endpoint_queue_limit( + const std::string& _address, std::uint16_t _port) const = 0; + virtual endpoint_queue_limit_t get_endpoint_queue_limit_local() const = 0; + + virtual std::uint32_t get_max_tcp_restart_aborts() const = 0; + virtual std::uint32_t get_max_tcp_connect_time() const = 0; + + // Acceptance handling + virtual bool is_protected_device( + const boost::asio::ip::address& _address) const = 0; + virtual bool is_protected_port( + const boost::asio::ip::address& _address, std::uint16_t _port, + bool _reliable) const = 0; + virtual bool is_secure_port( + const boost::asio::ip::address& _address, std::uint16_t _port, + bool _reliable) const = 0; + + typedef std::pair<std::uint16_t, std::uint16_t> port_range_t; + virtual void set_sd_acceptance_rule( + const boost::asio::ip::address &_address, + port_range_t _port_range, port_type_e _type, + const std::string &_path, bool _reliable, bool _enable, bool _default) = 0; + + typedef std::map< + boost::asio::ip::address, // other device + std::pair< + std::string, // path to file that determines whether or not IPsec is active + std::map< + bool, // false = unreliable (aka UDP), true = reliable (aka TCP) + std::pair< + boost::icl::interval_set<std::uint16_t>, // optional (aka semi-secure) port range + boost::icl::interval_set<std::uint16_t> // secure port range + > + > + > + > sd_acceptance_rules_t; + virtual sd_acceptance_rules_t get_sd_acceptance_rules() = 0; + virtual void set_sd_acceptance_rules_active( + const boost::asio::ip::address& _address, bool _enable) = 0; + + virtual bool is_secure_service(service_t _service, instance_t _instance) const = 0; + + virtual int get_udp_receive_buffer_size() const = 0; + + virtual bool check_routing_credentials(client_t _client, + const vsomeip_sec_client_t *_sec_client) const = 0; + + virtual bool check_suppress_events(service_t _service, + instance_t _instance, event_t _event) const = 0; + + // SOME/IP-TP + virtual bool is_tp_client( + service_t _service, instance_t _instance, + method_t _method) const = 0; + virtual bool is_tp_service( + service_t _service, instance_t _instance, + method_t _method) const = 0; + virtual void get_tp_configuration( + service_t _service, instance_t _instance, method_t _method, bool _is_client, + std::uint16_t &_max_segment_length, std::uint32_t &_separation_time) const = 0; + + // routing shutdown timeout + virtual std::uint32_t get_shutdown_timeout() const = 0; + + virtual bool log_statistics() const = 0; + virtual uint32_t get_statistics_interval() const = 0; + virtual uint32_t get_statistics_min_freq() const = 0; + virtual uint32_t get_statistics_max_messages() const = 0; + + virtual uint8_t get_max_remote_subscribers() const = 0; + + virtual partition_id_t get_partition_id( + service_t _service, instance_t _instance) const = 0; + + virtual reliability_type_e get_reliability_type( + const boost::asio::ip::address &_reliable_address, + const uint16_t &_reliable_port, + const boost::asio::ip::address &_unreliable_address, + const uint16_t &_unreliable_port) const = 0; + + // security + virtual bool is_security_enabled() const = 0; + virtual bool is_security_external() const = 0; + virtual bool is_security_audit() const = 0; + virtual bool is_remote_access_allowed() const = 0; + virtual std::shared_ptr<policy_manager_impl> get_policy_manager() const = 0; + virtual std::shared_ptr<security> get_security() const = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONFIGURATION_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_element.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_element.hpp new file mode 100644 index 00000000000..2b650e32a0a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_element.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CONFIGURATION_CONFIGURATION_ELEMENT_HPP_ +#define VSOMEIP_V3_CONFIGURATION_CONFIGURATION_ELEMENT_HPP_ + +#include <string> + +#include <boost/property_tree/ptree.hpp> + +namespace vsomeip_v3 { + +struct configuration_element { + std::string name_; + boost::property_tree::ptree tree_; + + configuration_element(const std::string &_name, const boost::property_tree::ptree &_tree) noexcept + : name_(_name), + tree_(_tree) { + } + + configuration_element(configuration_element &&_source) noexcept + : name_(std::move(_source.name_)), + tree_(std::move(_source.tree_)) { + } + + bool operator<(const configuration_element &_other) const { + return (name_ < _other.name_); + } +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONFIGURATION_CONFIGURATION_ELEMENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_impl.hpp new file mode 100644 index 00000000000..d9ed9cbc08a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_impl.hpp @@ -0,0 +1,691 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_CONFIGURATION_IMPL_HPP +#define VSOMEIP_V3_CFG_CONFIGURATION_IMPL_HPP + +#include <atomic> +#include <list> +#include <map> +#include <memory> +#include <mutex> +#include <unordered_set> +#include <vector> + +#include <boost/property_tree/ptree.hpp> + +#include "application_configuration.hpp" +#include "configuration.hpp" +#include "configuration_element.hpp" +#include "e2e.hpp" +#include "routing.hpp" +#include "watchdog.hpp" +#include "service_instance_range.hpp" +#include "trace.hpp" +#include "../../e2e_protection/include/e2exf/config.hpp" +#include "../../security/include/policy.hpp" + +namespace vsomeip_v3 { + +namespace cfg { + +struct client; +struct service; +struct servicegroup; +struct event; +struct eventgroup; +struct watchdog; + +struct suppress_t { + service_t service; + instance_t instance; + event_t event; + + inline bool operator<(const suppress_t& entry_) const { + if(service != entry_.service) { + return service < entry_.service; + } + if(instance != entry_.instance) { + return instance < entry_.instance; + } + if(event != entry_.event) { + return event < entry_.event; + } + return false; + } +}; + +class configuration_impl: + public configuration, + public std::enable_shared_from_this<configuration_impl> { +public: + VSOMEIP_EXPORT configuration_impl(const std::string &_path); + VSOMEIP_EXPORT configuration_impl(const configuration_impl &_other); + VSOMEIP_EXPORT virtual ~configuration_impl(); + + VSOMEIP_EXPORT bool load(const std::string &_name); +#ifndef VSOMEIP_DISABLE_SECURITY + VSOMEIP_EXPORT bool lazy_load_security(const std::string &_client_host); +#endif // !VSOMEIP_DISABLE_SECURITY + VSOMEIP_EXPORT bool remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled); + VSOMEIP_EXPORT bool remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote); + + VSOMEIP_EXPORT const std::string &get_network() const; + + VSOMEIP_EXPORT void set_configuration_path(const std::string &_path); + + VSOMEIP_EXPORT const boost::asio::ip::address & get_unicast_address() const; + VSOMEIP_EXPORT const boost::asio::ip::address& get_netmask() const; + VSOMEIP_EXPORT unsigned short get_prefix() const; + VSOMEIP_EXPORT const std::string &get_device() const; + VSOMEIP_EXPORT unsigned short get_diagnosis_address() const; + VSOMEIP_EXPORT std::uint16_t get_diagnosis_mask() const; + VSOMEIP_EXPORT bool is_v4() const; + VSOMEIP_EXPORT bool is_v6() const; + + VSOMEIP_EXPORT bool has_console_log() const; + VSOMEIP_EXPORT bool has_file_log() const; + VSOMEIP_EXPORT bool has_dlt_log() const; + VSOMEIP_EXPORT const std::string & get_logfile() const; + VSOMEIP_EXPORT vsomeip_v3::logger::level_e get_loglevel() const; + + VSOMEIP_EXPORT std::string get_unicast_address(service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT uint16_t get_reliable_port(service_t _service, instance_t _instance) const; + VSOMEIP_EXPORT bool has_enabled_magic_cookies(const std::string &_address, uint16_t _port) const; + VSOMEIP_EXPORT uint16_t get_unreliable_port(service_t _service, + instance_t _instance) const; + + VSOMEIP_EXPORT void get_configured_timing_requests( + service_t _service, const std::string &_ip_target, + std::uint16_t _port_target, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const; + VSOMEIP_EXPORT void get_configured_timing_responses( + service_t _service, const std::string &_ip_service, + std::uint16_t _port_service, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const; + + VSOMEIP_EXPORT bool is_someip(service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT bool get_client_port(service_t _service, instance_t _instance, + uint16_t _remote_port, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports, uint16_t &_client_port) const; + + VSOMEIP_EXPORT bool is_routing_enabled() const; + VSOMEIP_EXPORT bool is_local_routing() const; + + VSOMEIP_EXPORT const std::string &get_routing_host_name() const; + VSOMEIP_EXPORT const boost::asio::ip::address &get_routing_host_address() const; + VSOMEIP_EXPORT port_t get_routing_host_port() const; + + VSOMEIP_EXPORT const boost::asio::ip::address &get_routing_guest_address() const; + VSOMEIP_EXPORT std::set<std::pair<port_t, port_t> > get_routing_guest_ports( + uid_t _uid, gid_t _gid) const; + + VSOMEIP_EXPORT client_t get_id(const std::string &_name) const; + VSOMEIP_EXPORT bool is_configured_client_id(client_t _id) const; + + VSOMEIP_EXPORT std::size_t get_max_dispatchers(const std::string &_name) const; + VSOMEIP_EXPORT std::size_t get_max_dispatch_time(const std::string &_name) const; + VSOMEIP_EXPORT std::size_t get_max_detached_thread_wait_time(const std::string& _name) const; + VSOMEIP_EXPORT std::size_t get_io_thread_count(const std::string &_name) const; + VSOMEIP_EXPORT int get_io_thread_nice_level(const std::string &_name) const; + VSOMEIP_EXPORT std::size_t get_request_debouncing(const std::string &_name) const; + VSOMEIP_EXPORT bool has_session_handling(const std::string &_name) const; + + VSOMEIP_EXPORT std::set<std::pair<service_t, instance_t> > get_remote_services() const; + + VSOMEIP_EXPORT bool get_multicast(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, std::string &_address, uint16_t &_port) const; + + VSOMEIP_EXPORT uint8_t get_threshold(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const; + + VSOMEIP_EXPORT void get_event_update_properties( + service_t _service, instance_t _instance, event_t _event, + std::chrono::milliseconds &_cycle, + bool &_change_resets_cycle, bool &_update_on_change_) const; + + VSOMEIP_EXPORT std::uint32_t get_max_message_size_local() const; + VSOMEIP_EXPORT std::uint32_t get_max_message_size_reliable(const std::string& _address, + std::uint16_t _port) const; + VSOMEIP_EXPORT std::uint32_t get_max_message_size_unreliable() const; + VSOMEIP_EXPORT std::uint32_t get_buffer_shrink_threshold() const; + + VSOMEIP_EXPORT bool supports_selective_broadcasts(const boost::asio::ip::address &_address) const; + + VSOMEIP_EXPORT bool is_offered_remote(service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT bool log_version() const; + VSOMEIP_EXPORT uint32_t get_log_version_interval() const; + + VSOMEIP_EXPORT bool is_local_service(service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT reliability_type_e get_event_reliability( + service_t _service, instance_t _instance, event_t _event) const; + + VSOMEIP_EXPORT reliability_type_e get_service_reliability( + service_t _service, instance_t _instance) const; + + // Service Discovery configuration + VSOMEIP_EXPORT bool is_sd_enabled() const; + + VSOMEIP_EXPORT const std::string & get_sd_multicast() const; + VSOMEIP_EXPORT uint16_t get_sd_port() const; + VSOMEIP_EXPORT const std::string & get_sd_protocol() const; + + VSOMEIP_EXPORT uint32_t get_sd_initial_delay_min() const; + VSOMEIP_EXPORT uint32_t get_sd_initial_delay_max() const; + VSOMEIP_EXPORT int32_t get_sd_repetitions_base_delay() const; + VSOMEIP_EXPORT uint8_t get_sd_repetitions_max() const; + VSOMEIP_EXPORT ttl_t get_sd_ttl() const; + VSOMEIP_EXPORT int32_t get_sd_cyclic_offer_delay() const; + VSOMEIP_EXPORT int32_t get_sd_request_response_delay() const; + VSOMEIP_EXPORT std::uint32_t get_sd_offer_debounce_time() const; + VSOMEIP_EXPORT std::uint32_t get_sd_find_debounce_time() const; + + // Trace configuration + VSOMEIP_EXPORT std::shared_ptr<cfg::trace> get_trace() const; + + VSOMEIP_EXPORT bool is_watchdog_enabled() const; + VSOMEIP_EXPORT uint32_t get_watchdog_timeout() const; + VSOMEIP_EXPORT uint32_t get_allowed_missing_pongs() const; + + VSOMEIP_EXPORT std::uint32_t get_permissions_uds() const; + + VSOMEIP_EXPORT bool check_routing_credentials(client_t _client, + const vsomeip_sec_client_t *_sec_client) const; + + VSOMEIP_EXPORT bool check_suppress_events(service_t _service, + instance_t _instance, event_t _event) const; + + VSOMEIP_EXPORT std::map<plugin_type_e, std::set<std::string>> get_plugins( + const std::string &_name) const; + // E2E + VSOMEIP_EXPORT std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> get_e2e_configuration() const; + VSOMEIP_EXPORT bool is_e2e_enabled() const; + + VSOMEIP_EXPORT bool log_memory() const; + VSOMEIP_EXPORT uint32_t get_log_memory_interval() const; + + VSOMEIP_EXPORT bool log_status() const; + VSOMEIP_EXPORT uint32_t get_log_status_interval() const; + + VSOMEIP_EXPORT ttl_map_t get_ttl_factor_offers() const; + VSOMEIP_EXPORT ttl_map_t get_ttl_factor_subscribes() const; + + VSOMEIP_EXPORT std::shared_ptr<debounce_filter_impl_t> get_debounce( + const std::string &_name, + service_t _service, instance_t _instance, event_t _event) const; + + VSOMEIP_EXPORT endpoint_queue_limit_t get_endpoint_queue_limit( + const std::string& _address, std::uint16_t _port) const; + VSOMEIP_EXPORT endpoint_queue_limit_t get_endpoint_queue_limit_local() const; + + VSOMEIP_EXPORT std::uint32_t get_max_tcp_restart_aborts() const; + VSOMEIP_EXPORT std::uint32_t get_max_tcp_connect_time() const; + + VSOMEIP_EXPORT bool is_protected_device( + const boost::asio::ip::address& _address) const; + VSOMEIP_EXPORT bool is_protected_port( + const boost::asio::ip::address& _address, + std::uint16_t _port, bool _reliable) const; + VSOMEIP_EXPORT bool is_secure_port( + const boost::asio::ip::address& _address, + std::uint16_t _port, bool _reliable) const; + + VSOMEIP_EXPORT void set_sd_acceptance_rule( + const boost::asio::ip::address& _address, + port_range_t _port_range, port_type_e _type, + const std::string& _path, bool _reliable, bool _enable, bool _default); + VSOMEIP_EXPORT void set_sd_acceptance_rules( + const sd_acceptance_rules_t& _rules, bool _enable); + VSOMEIP_EXPORT sd_acceptance_rules_t get_sd_acceptance_rules(); + VSOMEIP_EXPORT void set_sd_acceptance_rules_active( + const boost::asio::ip::address& _address, bool _enable); + + VSOMEIP_EXPORT bool is_secure_service(service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT int get_udp_receive_buffer_size() const; + + VSOMEIP_EXPORT bool is_tp_client( + service_t _service, + instance_t _instance, + method_t _method) const; + VSOMEIP_EXPORT bool is_tp_service( + service_t _service, instance_t _instance, method_t _method) const; + VSOMEIP_EXPORT void get_tp_configuration( + service_t _service, instance_t _instance, method_t _method, bool _is_client, + std::uint16_t &_max_segment_length, std::uint32_t &_separation_time) const; + + VSOMEIP_EXPORT std::uint32_t get_shutdown_timeout() const; + + VSOMEIP_EXPORT bool log_statistics() const; + VSOMEIP_EXPORT uint32_t get_statistics_interval() const; + VSOMEIP_EXPORT uint32_t get_statistics_min_freq() const; + VSOMEIP_EXPORT uint32_t get_statistics_max_messages() const; + + VSOMEIP_EXPORT uint8_t get_max_remote_subscribers() const; + + VSOMEIP_EXPORT partition_id_t get_partition_id( + service_t _service, instance_t _instance) const; + + VSOMEIP_EXPORT std::map<std::string, std::string> get_additional_data( + const std::string &_application_name, + const std::string &_plugin_name); + + VSOMEIP_EXPORT reliability_type_e get_reliability_type( + const boost::asio::ip::address &_reliable_address, + const uint16_t &_reliable_port, + const boost::asio::ip::address &_unreliable_address, + const uint16_t &_unreliable_port) const; + + VSOMEIP_EXPORT bool is_security_enabled() const; + VSOMEIP_EXPORT bool is_security_external() const; + VSOMEIP_EXPORT bool is_security_audit() const; + VSOMEIP_EXPORT bool is_remote_access_allowed() const; + + VSOMEIP_EXPORT std::shared_ptr<policy_manager_impl> get_policy_manager() const; + VSOMEIP_EXPORT std::shared_ptr<security> get_security() const; +private: + void read_data(const std::set<std::string> &_input, + std::vector<configuration_element> &_elements, + std::set<std::string> &_failed, + bool _mandatory_only, bool _read_second_level = false); +#ifndef VSOMEIP_DISABLE_POLICY + void load_policy_data(const std::string &_input, + std::vector<configuration_element> &_elements, + std::set<std::string> &_failed, + bool _mandatory_only); +#endif // !VSOMEIP_DISABLE_POLICY + bool load_data(const std::vector<configuration_element> &_elements, + bool _load_mandatory, bool _load_optional); + + bool load_logging(const configuration_element &_element, + std::set<std::string> &_warnings); + + bool load_applications(const configuration_element &_element); + void load_application_data(const boost::property_tree::ptree &_tree, + const std::string &_file_name); + + std::map<plugin_type_e, std::set<std::string>> load_plugins( + const boost::property_tree::ptree &_tree, + const std::string &_application_name); + + struct plugin_config_data_t { + std::string name_; + std::string type_; + }; + + void add_plugin(std::map<plugin_type_e, std::set<std::string>> &_plugins, + const plugin_config_data_t &_plugin_data, + const std::string& _application_name); + + bool load_routing(const configuration_element &_element); + bool load_routing_host(const boost::property_tree::ptree &_tree, + const std::string &_name); + bool load_routing_guests(const boost::property_tree::ptree &_tree); + void load_routing_guest_ports(const boost::property_tree::ptree &_tree); + std::set<std::pair<port_t, port_t> > load_routing_guest_port_range( + const boost::property_tree::ptree &_tree) const; + + bool load_routing_credentials(const configuration_element &_element); // compatibility + void load_routing_client_ports(const configuration_element &_element); // compatibility + + void load_tracing(const configuration_element &_element); + void load_trace_channels(const boost::property_tree::ptree &_tree); + void load_trace_channel(const boost::property_tree::ptree &_tree); + void load_trace_filters(const boost::property_tree::ptree &_tree); + void load_trace_filter(const boost::property_tree::ptree &_tree); + void load_trace_filter_expressions( + const boost::property_tree::ptree &_tree, + std::string &_criteria, + std::shared_ptr<trace_filter> &_filter); + void load_trace_filter_match( + const boost::property_tree::ptree &_data, + std::tuple<service_t, instance_t, method_t> &_match); + + void load_suppress_events(const configuration_element &_element); + void load_suppress_events_data( + const boost::property_tree::ptree &_tree); + std::set<event_t> load_suppress_multiple_events( + const boost::property_tree::ptree &_tree); + uint16_t load_suppress_data(const std::string &_value) const; + std::set<event_t> load_range_events(event_t _first_event, + event_t _last_event) const ; + void insert_suppress_events(service_t _service, + instance_t _instance, event_t _event); + void print_suppress_events(void) const; + + void load_network(const configuration_element &_element); + void load_device(const configuration_element &_element); + + void load_unicast_address(const configuration_element &_element); + void load_netmask(const configuration_element &_element); + void load_diagnosis_address(const configuration_element &_element); + void load_shutdown_timeout(const configuration_element &_element); + + void load_service_discovery(const configuration_element &_element); + void load_delays(const boost::property_tree::ptree &_tree); + + void load_npdu_default_timings(const configuration_element &_element); + void load_services(const configuration_element &_element); + void load_servicegroup(const boost::property_tree::ptree &_tree); + void load_service(const boost::property_tree::ptree &_tree, + const std::string &_unicast_address); + void load_event(std::shared_ptr<service> &_service, + const boost::property_tree::ptree &_tree); + void load_eventgroup(std::shared_ptr<service> &_service, + const boost::property_tree::ptree &_tree); + + void load_internal_services(const configuration_element &_element); + + void load_clients(const configuration_element &_element); + void load_client(const boost::property_tree::ptree &_tree); + + std::set<uint16_t> load_client_ports(const boost::property_tree::ptree &_tree); + std::pair<uint16_t, uint16_t> load_client_port_range(const boost::property_tree::ptree &_tree); + + void load_watchdog(const configuration_element &_element); + + void load_payload_sizes(const configuration_element &_element); + void load_permissions(const configuration_element &_element); + + void load_security(const configuration_element &_element); + + void load_selective_broadcasts_support(const configuration_element &_element); + + void load_debounce(const configuration_element &_element); + void load_service_debounce(const boost::property_tree::ptree &_tree, + debounce_configuration_t &_debounces); + void load_events_debounce(const boost::property_tree::ptree &_tree, + std::map<event_t, std::shared_ptr<debounce_filter_impl_t> > &_debounces); + void load_event_debounce(const boost::property_tree::ptree &_tree, + std::map<event_t, std::shared_ptr<debounce_filter_impl_t> > &_debounces); + void load_event_debounce_ignore(const boost::property_tree::ptree &_tree, + std::map<std::size_t, byte_t> &_ignore); + void load_acceptances(const configuration_element &_element); + void load_acceptance_data(const boost::property_tree::ptree &_tree); + void load_udp_receive_buffer_size(const configuration_element &_element); + bool load_npdu_debounce_times_configuration( + const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree); + bool load_npdu_debounce_times_for_service( + const std::shared_ptr<service>& _service, bool _is_request, + const boost::property_tree::ptree &_tree); + void load_someip_tp(const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree); + void load_someip_tp_for_service( + const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree, bool _is_request); + + servicegroup *find_servicegroup(const std::string &_name) const; + std::shared_ptr<client> find_client(service_t _service, + instance_t _instance) const; + std::shared_ptr<service> find_service(service_t _service, instance_t _instance) const; + std::shared_ptr<service> find_service_unlocked(service_t _service, instance_t _instance) const; + std::shared_ptr<service> find_service(service_t _service, + const std::string &_address, std::uint16_t _port) const; + std::shared_ptr<eventgroup> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + bool find_port(uint16_t &_port, uint16_t _remote, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports) const; + bool find_specific_port(uint16_t &_port, service_t _service, + instance_t _instance, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports) const; + + void set_magic_cookies_unicast_address(); + + bool is_mandatory(const std::string &_name) const; + bool is_remote(const std::shared_ptr<service>& _service) const; + bool is_internal_service(service_t _service, instance_t _instance) const; + bool is_in_port_range(uint16_t _port, std::pair<uint16_t, uint16_t> _port_range) const; + + void set_mandatory(const std::string &_input); + void trim(std::string &_s); + + void load_e2e(const configuration_element &_element); + void load_e2e_protected(const boost::property_tree::ptree &_tree); + + void load_ttl_factors(const boost::property_tree::ptree &_tree, + ttl_map_t* _target); + + void load_endpoint_queue_sizes(const configuration_element &_element); + + void load_tcp_restart_settings(const configuration_element &_element); + + void load_secure_services(const configuration_element &_element); + void load_secure_service(const boost::property_tree::ptree &_tree); + + void load_partitions(const configuration_element &_element); + void load_partition(const boost::property_tree::ptree &_tree); + +private: + std::mutex mutex_; + + const std::string default_unicast_; + bool is_loaded_; + bool is_logging_loaded_; + + std::set<std::string> mandatory_; + + std::shared_ptr<policy_manager_impl> policy_manager_; + std::shared_ptr<security> security_; + +protected: + // Configuration data + boost::asio::ip::address unicast_; + boost::asio::ip::address netmask_; + unsigned short prefix_; + std::string device_; + diagnosis_t diagnosis_; + diagnosis_t diagnosis_mask_; + + std::atomic_bool has_console_log_; + std::atomic_bool has_file_log_; + std::atomic_bool has_dlt_log_; + std::string logfile_; + mutable std::mutex mutex_loglevel_; + vsomeip_v3::logger::level_e loglevel_; + + std::map< + std::string, + application_configuration + > applications_; + std::set<client_t> client_identifiers_; + + mutable std::mutex services_mutex_; + std::map<service_t, + std::map<instance_t, + std::shared_ptr<service> > > services_; + + std::map<std::string, // IP + std::map<std::uint16_t, // port + std::map<service_t, + std::shared_ptr<service>>>> services_by_ip_port_; + + std::set<suppress_t> suppress_events_; + bool is_suppress_events_enabled_; + + std::list< std::shared_ptr<client> > clients_; + + routing_t routing_; + + bool is_sd_enabled_; + std::string sd_protocol_; + std::string sd_multicast_; + uint16_t sd_port_; + + uint32_t sd_initial_delay_min_; + uint32_t sd_initial_delay_max_; + int32_t sd_repetitions_base_delay_; + uint8_t sd_repetitions_max_; + ttl_t sd_ttl_; + int32_t sd_cyclic_offer_delay_; + int32_t sd_request_response_delay_; + std::uint32_t sd_offer_debounce_time_; + std::uint32_t sd_find_debounce_time_; + + std::map<std::string, std::set<uint16_t> > magic_cookies_; + + std::map<std::string, std::map<std::uint16_t, std::uint32_t>> message_sizes_; + std::uint32_t max_configured_message_size_; + std::uint32_t max_local_message_size_; + std::uint32_t max_reliable_message_size_; + std::uint32_t max_unreliable_message_size_; + std::uint32_t buffer_shrink_threshold_; + + std::shared_ptr<trace> trace_; + + std::unordered_set<std::string> supported_selective_addresses; + + std::shared_ptr<watchdog> watchdog_; + + std::vector<service_instance_range> internal_service_ranges_; + + bool log_version_; + uint32_t log_version_interval_; + + enum element_type_e { + ET_NETWORK, + ET_UNICAST, + ET_DEVICE, + ET_DIAGNOSIS, + ET_DIAGNOSIS_MASK, + ET_LOGGING_CONSOLE, + ET_LOGGING_FILE, + ET_LOGGING_DLT, + ET_LOGGING_LEVEL, + ET_ROUTING, + ET_SERVICE_DISCOVERY_ENABLE, + ET_SERVICE_DISCOVERY_PROTOCOL, + ET_SERVICE_DISCOVERY_MULTICAST, + ET_SERVICE_DISCOVERY_PORT, + ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN, + ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX, + ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY, + ET_SERVICE_DISCOVERY_REPETITION_MAX, + ET_SERVICE_DISCOVERY_TTL, + ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY, + ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY, + ET_WATCHDOG_ENABLE, + ET_WATCHDOG_TIMEOUT, + ET_WATCHDOG_ALLOWED_MISSING_PONGS, + ET_TRACING_ENABLE, + ET_TRACING_SD_ENABLE, + ET_SERVICE_DISCOVERY_OFFER_DEBOUNCE_TIME, + ET_SERVICE_DISCOVERY_FIND_DEBOUNCE_TIME, + ET_SERVICE_DISCOVERY_TTL_FACTOR_OFFERS, + ET_SERVICE_DISCOVERY_TTL_FACTOR_SUBSCRIPTIONS, + ET_ENDPOINT_QUEUE_LIMITS, + ET_ENDPOINT_QUEUE_LIMIT_EXTERNAL, + ET_ENDPOINT_QUEUE_LIMIT_LOCAL, + ET_TCP_RESTART_ABORTS_MAX, + ET_TCP_CONNECT_TIME_MAX, + ET_SD_ACCEPTANCE_REQUIRED, + ET_NETMASK, + ET_UDP_RECEIVE_BUFFER_SIZE, + ET_NPDU_DEFAULT_TIMINGS, + ET_PLUGIN_NAME, + ET_PLUGIN_TYPE, + ET_SHUTDOWN_TIMEOUT, + ET_MAX_REMOTE_SUBSCRIBERS, + ET_PARTITIONS, + ET_SECURITY_AUDIT_MODE, + ET_SECURITY_REMOTE_ACCESS, + ET_MAX = 46 + }; + + bool is_configured_[ET_MAX]; + std::uint32_t permissions_uds_; + + std::string network_; + std::string configuration_path_; + + bool e2e_enabled_; + std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> e2e_configuration_; + + bool log_memory_; + uint32_t log_memory_interval_; + + bool log_status_; + uint32_t log_status_interval_; + + ttl_map_t ttl_factors_offers_; + ttl_map_t ttl_factors_subscriptions_; + + debounce_configuration_t debounces_; + + std::map<std::string, std::map<std::uint16_t, endpoint_queue_limit_t>> endpoint_queue_limits_; + endpoint_queue_limit_t endpoint_queue_limit_external_; + endpoint_queue_limit_t endpoint_queue_limit_local_; + + uint32_t tcp_restart_aborts_max_; + uint32_t tcp_connect_time_max_; + + mutable std::mutex sd_acceptance_required_ips_mutex_; + sd_acceptance_rules_t sd_acceptance_rules_; + std::set<boost::asio::ip::address> sd_acceptance_rules_active_; + + bool has_issued_methods_warning_; + bool has_issued_clients_warning_; + + int udp_receive_buffer_size_; + + std::chrono::nanoseconds npdu_default_debounce_requ_; + std::chrono::nanoseconds npdu_default_debounce_resp_; + std::chrono::nanoseconds npdu_default_max_retention_requ_; + std::chrono::nanoseconds npdu_default_max_retention_resp_; + + std::uint32_t shutdown_timeout_; + + mutable std::mutex secure_services_mutex_; + std::map<service_t, std::set<instance_t> > secure_services_; + + bool log_statistics_; + uint32_t statistics_interval_; + uint32_t statistics_min_freq_; + uint32_t statistics_max_messages_; + + uint8_t max_remote_subscribers_; + + mutable std::mutex partitions_mutex_; + std::map<service_t, + std::map<instance_t, + partition_id_t + > + > partitions_; + + std::string path_; + + std::map<std::string, + std::map<std::string, + std::map<std::string, + std::string + > + > + > plugins_additional_; + + std::atomic_bool is_security_enabled_; + std::atomic_bool is_security_external_; + std::atomic_bool is_security_audit_; + std::atomic_bool is_remote_access_allowed_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_CONFIGURATION_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin.hpp new file mode 100644 index 00000000000..e9835a76342 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CONFIGURATION_PLUGIN_HPP_ +#define VSOMEIP_V3_CONFIGURATION_PLUGIN_HPP_ + +#include <string> +#include <memory> + +#define VSOMEIP_CONFIG_PLUGIN_VERSION 1 + +namespace vsomeip_v3 { + +class configuration; + +class configuration_plugin { +public: + virtual ~configuration_plugin() = default; + virtual std::shared_ptr<configuration> get_configuration( + const std::string &_name, const std::string &_path) = 0; + virtual bool remove_configuration(const std::string &_name) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONFIGURATION_PLUGIN_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin_impl.hpp new file mode 100644 index 00000000000..79c47b63b9c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/configuration_plugin_impl.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CONFIGURATION_CONFIGURATION_PLUGIN_IMPL_HPP_ +#define VSOMEIP_V3_CONFIGURATION_CONFIGURATION_PLUGIN_IMPL_HPP_ + +#include <map> +#include <mutex> + +#include <vsomeip/plugin.hpp> + +#include "configuration_plugin.hpp" + +namespace vsomeip_v3 { +namespace cfg { + + class configuration_impl; + +} // namespace cfg + +class configuration_plugin_impl + : public configuration_plugin, + public plugin_impl<configuration_plugin_impl> { +public: + configuration_plugin_impl(); + virtual ~configuration_plugin_impl(); + + std::shared_ptr<configuration> get_configuration(const std::string &_name, + const std::string &_path); + bool remove_configuration(const std::string &_name); + +private: + std::mutex mutex_; + std::map<std::string, std::shared_ptr<cfg::configuration_impl> > configurations_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONFIGURATION_CONFIGURATION_PLUGIN_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/debounce_filter_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/debounce_filter_impl.hpp new file mode 100644 index 00000000000..80696af834b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/debounce_filter_impl.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_DEBOUNCE_HPP +#define VSOMEIP_V3_DEBOUNCE_HPP + +#include <vsomeip/structured_types.hpp> + +namespace vsomeip_v3 { + +// Additionally store the last forwarded timestamp to +// avoid having to lock +struct debounce_filter_impl_t : debounce_filter_t { + debounce_filter_impl_t() + : last_forwarded_(std::chrono::steady_clock::time_point::max()) { + } + + explicit debounce_filter_impl_t(const debounce_filter_t &_source) + : debounce_filter_t(_source), + last_forwarded_(std::chrono::steady_clock::time_point::max()) { + } + + std::chrono::steady_clock::time_point last_forwarded_; +}; + +using debounce_configuration_t = + std::map<service_t, + std::map<instance_t, + std::map<event_t, + std::shared_ptr<debounce_filter_impl_t>>>>; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_DEBOUNCE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/e2e.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/e2e.hpp new file mode 100644 index 00000000000..2660756f4c9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/e2e.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_E2E_HPP_ +#define VSOMEIP_V3_CFG_E2E_HPP_ + +#include <map> +#include <string> +#include <vector> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct e2e { + typedef std::map<std::string, std::string> custom_parameters_t; + + e2e() : + variant(""), + profile(""), + service_id(0), + event_id(0) { + } + + e2e(const std::string &_variant, const std::string &_profile, service_t _service_id, + event_t _event_id, custom_parameters_t&& _custom_parameters) : + variant(_variant), + profile(_profile), + service_id(_service_id), + event_id(_event_id), + custom_parameters(_custom_parameters) { + } + + // common config + std::string variant; + std::string profile; + service_t service_id; + event_t event_id; + + // custom parameters + custom_parameters_t custom_parameters; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_E2E_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/event.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/event.hpp new file mode 100644 index 00000000000..1e35a85f091 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/event.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_EVENT_HPP +#define VSOMEIP_V3_CFG_EVENT_HPP + +#include <memory> +#include <vector> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct eventgroup; + +struct event { + event(event_t _id, bool _is_field, reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change) + : id_(_id), + is_field_(_is_field), + reliability_(_reliability), + cycle_(_cycle), + change_resets_cycle_(_change_resets_cycle), + update_on_change_(_update_on_change) { + } + + event_t id_; + bool is_field_; + reliability_type_e reliability_; + std::vector<std::weak_ptr<eventgroup> > groups_; + + std::chrono::milliseconds cycle_; + bool change_resets_cycle_; + bool update_on_change_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_EVENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/eventgroup.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/eventgroup.hpp new file mode 100644 index 00000000000..328a02db7c2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/eventgroup.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_EVENTGROUP_HPP +#define VSOMEIP_V3_CFG_EVENTGROUP_HPP + +#include <memory> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct event; + +struct eventgroup { + eventgroup_t id_; + std::set<std::shared_ptr<event> > events_; + std::string multicast_address_; + uint16_t multicast_port_; + uint8_t threshold_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_EVENTGROUP_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal.hpp.in b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal.hpp.in new file mode 100644 index 00000000000..7a188fef4cd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal.hpp.in @@ -0,0 +1,172 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_INTERNAL_HPP_ +#define VSOMEIP_V3_INTERNAL_HPP_ + +#include <cstdint> +#include <limits> +#include <memory> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/structured_types.hpp> + +#define VSOMEIP_ENV_APPLICATION_NAME "VSOMEIP_APPLICATION_NAME" +#define VSOMEIP_ENV_CONFIGURATION "VSOMEIP_CONFIGURATION" +#define VSOMEIP_ENV_CONFIGURATION_MODULE "VSOMEIP_CONFIGURATION_MODULE" +#define VSOMEIP_ENV_E2E_PROTECTION_MODULE "VSOMEIP_E2E_PROTECTION_MODULE" +#define VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES "VSOMEIP_MANDATORY_CONFIGURATION_FILES" +#define VSOMEIP_ENV_LOAD_PLUGINS "VSOMEIP_LOAD_PLUGINS" +#define VSOMEIP_ENV_CLIENTSIDELOGGING "VSOMEIP_CLIENTSIDELOGGING" + +#define VSOMEIP_DEFAULT_CONFIGURATION_FILE "@DEFAULT_CONFIGURATION_FILE@" +#define VSOMEIP_LOCAL_CONFIGURATION_FILE "./vsomeip.json" +#define VSOMEIP_MANDATORY_CONFIGURATION_FILES "vsomeip_std.json,vsomeip_app.json,vsomeip_events.json,vsomeip_plc.json,vsomeip_log.json,vsomeip_security.json,vsomeip_whitelist.json,vsomeip_policy_extensions.json,vsomeip_portcfg.json" + +#define VSOMEIP_DEFAULT_CONFIGURATION_FOLDER "@DEFAULT_CONFIGURATION_FOLDER@" +#define VSOMEIP_DEBUG_CONFIGURATION_FOLDER "/var/opt/public/sin/vsomeip/" +#define VSOMEIP_LOCAL_CONFIGURATION_FOLDER "./vsomeip" + +#define VSOMEIP_BASE_PATH "@VSOMEIP_BASE_PATH@/" + +#define VSOMEIP_ROUTING_HOST_PORT_DEFAULT 31490 + +#ifdef _WIN32 +#define VSOMEIP_CFG_LIBRARY "vsomeip3-cfg.dll" +#else +#define VSOMEIP_CFG_LIBRARY "libvsomeip3-cfg.so.@VSOMEIP_MAJOR_VERSION@" +#endif + +#ifdef _WIN32 +#define VSOMEIP_SD_LIBRARY "vsomeip3-sd.dll" +#else +#define VSOMEIP_SD_LIBRARY "libvsomeip3-sd.so.@VSOMEIP_MAJOR_VERSION@" +#endif + +#ifdef _WIN32 +#define VSOMEIP_E2E_LIBRARY "vsomeip3-e2e.dll" +#else +#define VSOMEIP_E2E_LIBRARY "libvsomeip3-e2e.so.@VSOMEIP_MAJOR_VERSION@" +#endif + +#ifdef _WIN32 +#define VSOMEIP_SEC_LIBRARY "vsomeip_sec.dll" +#else +#define VSOMEIP_SEC_LIBRARY "libvsomeip-sec.so.1" +#endif + +#define VSOMEIP_ROUTING_CLIENT 0 + +#define VSOMEIP_CLIENT_UNSET 0xFFFF + +#ifdef _WIN32 +#define VSOMEIP_INTERNAL_BASE_PORT 51234 +#define __func__ __FUNCTION__ +#endif + +#define VSOMEIP_UNICAST_ADDRESS "@VSOMEIP_UNICAST_ADDRESS@" +#define VSOMEIP_NETMASK "255.255.255.0" +#define VSOMEIP_PREFIX 24 + +#define VSOMEIP_DEFAULT_CONNECT_TIMEOUT 100 +#define VSOMEIP_MAX_CONNECT_TIMEOUT 1600 +#define VSOMEIP_DEFAULT_CONNECTING_TIMEOUT 500 +#define VSOMEIP_DEFAULT_FLUSH_TIMEOUT 1000 +#define VSOMEIP_ROUTING_ROOT_RECONNECT_RETRIES 10000 +#define VSOMEIP_ROUTING_ROOT_RECONNECT_INTERVAL 10 // miliseconds + +#define VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT 5000 + +#define VSOMEIP_DEFAULT_QUEUE_WARN_SIZE 102400 + +#define VSOMEIP_MAX_TCP_CONNECT_TIME 5000 +#define VSOMEIP_MAX_TCP_RESTART_ABORTS 5 +#define VSOMEIP_MAX_TCP_SENT_WAIT_TIME 10000 + +#define VSOMEIP_MAX_NETLINK_RETRIES 3 + +#define VSOMEIP_TP_MAX_SEGMENT_LENGTH_DEFAULT 1392 + +#define VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD 5 + +#define VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT 5000 +#define VSOMEIP_DEFAULT_MAX_MISSING_PONGS 3 + +#define VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE 1703936 + +#define VSOMEIP_DEFAULT_IO_THREAD_COUNT 2 +#define VSOMEIP_DEFAULT_IO_THREAD_NICE_LEVEL 0 + +#define VSOMEIP_MAX_DISPATCHERS 10 +#define VSOMEIP_MAX_DISPATCH_TIME 100 + +#define VSOMEIP_MAX_WAIT_TIME_DETACHED_THREADS 5 + +#define VSOMEIP_REQUEST_DEBOUNCE_TIME 10 +#define VSOMEIP_DEFAULT_STATISTICS_MAX_MSG 50 +#define VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ 50 +#define VSOMEIP_DEFAULT_STATISTICS_INTERVAL 10000 + +#define VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS 3 + +#define VSOMEIP_MAX_WAIT_SENT 5 + +#define VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE 19 + +#define VSOMEIP_MINIMUM_CHECK_TTL_TIMEOUT 100 +#define VSOMEIP_SETSOCKOPT_TIMEOUT_US 500000 // us + +#define LOCAL_TCP_PORT_WAIT_TIME @VSOMEIP_LOCAL_TCP_PORT_WAIT_TIME@ +#define LOCAL_TCP_PORT_MAX_WAIT_TIME @VSOMEIP_LOCAL_TCP_PORT_MAX_WAIT_TIME@ + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <pthread.h> +#endif + +#define VSOMEIP_DATA_ID 0x677D +#define VSOMEIP_DIAGNOSIS_ADDRESS @VSOMEIP_DIAGNOSIS_ADDRESS@ + +#define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 +#define VSOMEIP_DEFAULT_UDS_PERMISSIONS 0666 + +#define VSOMEIP_ROUTING_READY_MESSAGE "@VSOMEIP_ROUTING_READY_MESSAGE@" + +#ifndef VSOMEIP_VERSION +#define VSOMEIP_VERSION "unknown version" +#endif + +namespace vsomeip_v3 { + +typedef enum { + SUBSCRIPTION_ACKNOWLEDGED, + SUBSCRIPTION_NOT_ACKNOWLEDGED, + IS_SUBSCRIBING +} subscription_state_e; + +inline constexpr std::uint32_t MESSAGE_SIZE_UNLIMITED = (std::numeric_limits<std::uint32_t>::max)(); + +inline constexpr std::uint32_t QUEUE_SIZE_UNLIMITED = (std::numeric_limits<std::uint32_t>::max)(); + +#define VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO 2 * 1000 * 1000 +#define VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO 5 * 1000 * 1000 + +inline constexpr std::uint32_t MAX_RECONNECTS_UNLIMITED = (std::numeric_limits<std::uint32_t>::max)(); + +const uid_t ANY_UID = 0xFFFFFFFF; +const gid_t ANY_GID = 0xFFFFFFFF; + +enum class port_type_e { + PT_OPTIONAL, + PT_SECURE, + PT_UNSECURE, + PT_UNKNOWN +}; + +using partition_id_t = std::uint8_t; +const partition_id_t VSOMEIP_DEFAULT_PARTITION_ID = 0; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_INTERNAL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal_android.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal_android.hpp new file mode 100644 index 00000000000..b9631b041a0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/internal_android.hpp @@ -0,0 +1,162 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_INTERNAL_HPP_ +#define VSOMEIP_V3_INTERNAL_HPP_ + +#include <cstdint> +#include <limits> +#include <memory> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/structured_types.hpp> + +#define VSOMEIP_ENV_APPLICATION_NAME "VSOMEIP_APPLICATION_NAME" +#define VSOMEIP_ENV_CONFIGURATION "VSOMEIP_CONFIGURATION" +#define VSOMEIP_ENV_CONFIGURATION_MODULE "VSOMEIP_CONFIGURATION_MODULE" +#define VSOMEIP_ENV_E2E_PROTECTION_MODULE "VSOMEIP_E2E_PROTECTION_MODULE" +#define VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES "VSOMEIP_MANDATORY_CONFIGURATION_FILES" +#define VSOMEIP_ENV_LOAD_PLUGINS "VSOMEIP_LOAD_PLUGINS" +#define VSOMEIP_ENV_CLIENTSIDELOGGING "VSOMEIP_CLIENTSIDELOGGING" + +#define VSOMEIP_DEFAULT_CONFIGURATION_FILE "/vendor/run/etc/vsomeip.json" +#define VSOMEIP_LOCAL_CONFIGURATION_FILE "./vsomeip.json" +#define VSOMEIP_MANDATORY_CONFIGURATION_FILES \ + "vsomeip_std.json,vsomeip_app.json,vsomeip_events.json,vsomeip_plc.json,vsomeip_log.json," \ + "vsomeip_security.json,vsomeip_whitelist.json,vsomeip_policy_extensions.json,vsomeip_portcfg." \ + "json" + +#define VSOMEIP_DEFAULT_CONFIGURATION_FOLDER "/vendor/run/etc/vsomeip" +#define VSOMEIP_DEBUG_CONFIGURATION_FOLDER "/var/opt/public/sin/vsomeip/" +#define VSOMEIP_LOCAL_CONFIGURATION_FOLDER "./vsomeip" + +// VSOMEIP_BASE_PATH should be specified in Android.bp or/and Android.mk file via c/c++ compiler flags. +// #define VSOMEIP_BASE_PATH "/storage/" + +#define VSOMEIP_ROUTING_HOST_PORT_DEFAULT 31490 + +#define VSOMEIP_CFG_LIBRARY "libvsomeip_cfg.so" + +#define VSOMEIP_SD_LIBRARY "libvsomeip_sd.so" + +#define VSOMEIP_E2E_LIBRARY "libvsomeip_e2e.so" + +#define VSOMEIP_SEC_LIBRARY "libvsomeip-sec.so.1" + +#define VSOMEIP_ROUTING "vsomeipd" +#define VSOMEIP_ROUTING_CLIENT 0 +#define VSOMEIP_ROUTING_INFO_SIZE_INIT 256 + +#define VSOMEIP_CLIENT_UNSET 0xFFFF + +#define VSOMEIP_UNICAST_ADDRESS "127.0.0.1" +#define VSOMEIP_NETMASK "255.255.255.0" +#define VSOMEIP_PREFIX 24 + +#define VSOMEIP_DEFAULT_CONNECT_TIMEOUT 100 +#define VSOMEIP_MAX_CONNECT_TIMEOUT 1600 +#define VSOMEIP_DEFAULT_CONNECTING_TIMEOUT 500 +#define VSOMEIP_DEFAULT_FLUSH_TIMEOUT 1000 +#define VSOMEIP_ROUTING_ROOT_RECONNECT_RETRIES 10000 +#define VSOMEIP_ROUTING_ROOT_RECONNECT_INTERVAL 10 // miliseconds + +#define VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT 5000 + +#define VSOMEIP_DEFAULT_QUEUE_WARN_SIZE 102400 + +#define VSOMEIP_MAX_TCP_CONNECT_TIME 5000 +#define VSOMEIP_MAX_TCP_RESTART_ABORTS 5 +#define VSOMEIP_MAX_TCP_SENT_WAIT_TIME 10000 + +#define VSOMEIP_MAX_NETLINK_RETRIES 3 + +#define VSOMEIP_TP_MAX_SEGMENT_LENGTH_DEFAULT 1392 + +#define VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD 5 + +#define VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT 5000 +#define VSOMEIP_DEFAULT_MAX_MISSING_PONGS 3 + +#define VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE 1703936 + +#define VSOMEIP_DEFAULT_IO_THREAD_COUNT 2 +#define VSOMEIP_DEFAULT_IO_THREAD_NICE_LEVEL 0 + +#define VSOMEIP_MAX_DISPATCHERS 10 +#define VSOMEIP_MAX_DISPATCH_TIME 100 + +#define VSOMEIP_MAX_WAIT_TIME_DETACHED_THREADS 5 + +#define VSOMEIP_REQUEST_DEBOUNCE_TIME 10 +#define VSOMEIP_DEFAULT_STATISTICS_MAX_MSG 50 +#define VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ 50 +#define VSOMEIP_DEFAULT_STATISTICS_INTERVAL 10000 + +#define VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS 3 + +#define VSOMEIP_MAX_WAIT_SENT 5 + +#define VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE 19 + +#define VSOMEIP_MINIMUM_CHECK_TTL_TIMEOUT 100 +#define VSOMEIP_SETSOCKOPT_TIMEOUT_US 500000 // us + +#define LOCAL_TCP_PORT_WAIT_TIME 100 +#define LOCAL_TCP_PORT_MAX_WAIT_TIME 10000 + +#include <pthread.h> + +#define VSOMEIP_DATA_ID 0x677D +#define VSOMEIP_DIAGNOSIS_ADDRESS 0x01 + +#define VSOMEIP_DEFAULT_SHM_PERMISSION 0666 +#define VSOMEIP_DEFAULT_UDS_PERMISSIONS 0666 + +#define VSOMEIP_ROUTING_READY_MESSAGE "SOME/IP routing ready." + +#ifndef VSOMEIP_VERSION +#define VSOMEIP_VERSION "unknown version" +#endif + +namespace vsomeip_v3 { + +typedef enum { + RIE_ADD_CLIENT = 0x0, + RIE_ADD_SERVICE_INSTANCE = 0x1, + RIE_DEL_SERVICE_INSTANCE = 0x2, + RIE_DEL_CLIENT = 0x3, +} routing_info_entry_e; + +typedef enum { + SUBSCRIPTION_ACKNOWLEDGED, + SUBSCRIPTION_NOT_ACKNOWLEDGED, + IS_SUBSCRIBING +} subscription_state_e; + +inline constexpr std::uint32_t MESSAGE_SIZE_UNLIMITED = std::numeric_limits<std::uint32_t>::max(); + +inline constexpr std::uint32_t QUEUE_SIZE_UNLIMITED = std::numeric_limits<std::uint32_t>::max(); + +#define VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO 2 * 1000 * 1000 +#define VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO 5 * 1000 * 1000 + +inline constexpr std::uint32_t MAX_RECONNECTS_UNLIMITED = std::numeric_limits<std::uint32_t>::max(); + +inline constexpr std::uint32_t ANY_UID = 0xFFFFFFFF; +inline constexpr std::uint32_t ANY_GID = 0xFFFFFFFF; + +enum class port_type_e { + PT_OPTIONAL, + PT_SECURE, + PT_UNSECURE, + PT_UNKNOWN +}; + +typedef uint8_t partition_id_t; +const partition_id_t VSOMEIP_DEFAULT_PARTITION_ID = 0; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_INTERNAL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/routing.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/routing.hpp new file mode 100644 index 00000000000..b2929695240 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/routing.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_ROUTING_HPP_ +#define VSOMEIP_V3_CFG_ROUTING_HPP_ + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/primitive_types.hpp> + +#ifdef ANDROID +#include "internal_android.hpp" +#else +#include "internal.hpp" +#endif + +namespace vsomeip_v3 { +namespace cfg { + +struct routing_host_t { + std::string name_; + boost::asio::ip::address unicast_; + port_t port_; + + routing_host_t() : port_(VSOMEIP_ROUTING_HOST_PORT_DEFAULT) {} + + routing_host_t &operator=(const routing_host_t &_other) { + name_ = _other.name_; + unicast_ = _other.unicast_; + port_ = _other.port_; + + return *this; + } +}; + +struct routing_guests_t { + boost::asio::ip::address unicast_; + std::map<std::pair<uid_t, gid_t>, + std::set<std::pair<port_t, port_t> > + > ports_; + + routing_guests_t &operator=(const routing_guests_t &_other) { + unicast_ = _other.unicast_; + ports_ = _other.ports_; + + return *this; + } +}; + +struct routing_t { + bool is_enabled_; + + routing_host_t host_; + routing_guests_t guests_; + + routing_t() : is_enabled_(true) {} + + routing_t &operator=(const routing_t &_other) { + is_enabled_ = _other.is_enabled_; + host_ = _other.host_; + guests_ = _other.guests_; + + return *this; + } +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_ROUTING_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service.hpp new file mode 100644 index 00000000000..982e5248609 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_SERVICE_HPP +#define VSOMEIP_V3_CFG_SERVICE_HPP + +#include <memory> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct event; +struct eventgroup; + +struct service { + service_t service_; + instance_t instance_; + + std::string unicast_address_; + + uint16_t reliable_; + uint16_t unreliable_; + + std::string multicast_address_; + uint16_t multicast_port_; + + std::string protocol_; + + // [0] = debounce_time + // [1] = retention_time + typedef std::map<method_t, std::array<std::chrono::nanoseconds, 2>> npdu_time_configuration_t; + npdu_time_configuration_t debounce_times_requests_; + npdu_time_configuration_t debounce_times_responses_; + + std::map<event_t, std::shared_ptr<event> > events_; + std::map<eventgroup_t, std::shared_ptr<eventgroup> > eventgroups_; + + // SOME/IP-TP + std::map<method_t, std::pair<uint16_t, uint32_t> > tp_client_config_; + std::map<method_t, std::pair<uint16_t, uint32_t> > tp_service_config_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service_instance_range.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service_instance_range.hpp new file mode 100644 index 00000000000..9ae162f7760 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/service_instance_range.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_SERVICE_INSTANCE_RANGE_HPP +#define VSOMEIP_V3_CFG_SERVICE_INSTANCE_RANGE_HPP + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace cfg { + +struct service_instance_range { + service_t first_service_; + service_t last_service_; + instance_t first_instance_; + instance_t last_instance_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_SERVICE_INSTANCE_RANGE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/trace.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/trace.hpp new file mode 100644 index 00000000000..a83aa81cac9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/trace.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CFG_TRACE_HPP_ +#define VSOMEIP_V3_CFG_TRACE_HPP_ + +#include <string> +#include <vector> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/trace.hpp> +#include "../../tracing/include/enumeration_types.hpp" + +namespace vsomeip_v3 { +namespace cfg { + +struct trace_channel { + trace_channel_t id_; + std::string name_; +}; + +struct trace_filter { + trace_filter() + : ftype_(vsomeip_v3::trace::filter_type_e::POSITIVE), + is_range_(false) { + } + + std::vector<trace_channel_t> channels_; + vsomeip_v3::trace::filter_type_e ftype_; + bool is_range_; + std::vector<vsomeip_v3::trace::match_t> matches_; +}; + +struct trace { + trace() + : is_enabled_(false), + is_sd_enabled_(false), + channels_(), + filters_() { + } + + bool is_enabled_; + bool is_sd_enabled_; + + std::vector<std::shared_ptr<trace_channel>> channels_; + std::vector<std::shared_ptr<trace_filter>> filters_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_TRACE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/watchdog.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/watchdog.hpp new file mode 100644 index 00000000000..5c9de1c1ff1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/include/watchdog.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_V3_CFG_WATCHDOG_HPP_ +#define VSOMEIP_V3_CFG_WATCHDOG_HPP_ + +namespace vsomeip_v3 { +namespace cfg { + +struct watchdog { + watchdog() + : is_enabeled_(false), + timeout_in_ms_(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT), + missing_pongs_allowed_(VSOMEIP_DEFAULT_MAX_MISSING_PONGS) { + } + + bool is_enabeled_; + uint32_t timeout_in_ms_; + uint32_t missing_pongs_allowed_; +}; + +} // namespace cfg +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CFG_WATCHDOG_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_impl.cpp new file mode 100644 index 00000000000..4e82151003c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_impl.cpp @@ -0,0 +1,5069 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cctype> +#include <fstream> +#include <functional> +#include <limits> +#include <mutex> +#include <set> +#include <sstream> +#include <utility> + +#define WIN32_LEAN_AND_MEAN +#define BOOST_BIND_GLOBAL_PLACEHOLDERS + +#include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <boost/asio/ip/address.hpp> +#include <boost/property_tree/json_parser.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/plugins/pre_configuration_plugin.hpp> +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/structured_types.hpp> +#include <vsomeip/internal/plugin_manager.hpp> + +#include "../include/client.hpp" +#include "../include/configuration_impl.hpp" +#include "../include/event.hpp" +#include "../include/eventgroup.hpp" +#include "../include/service.hpp" +#include "../../logger/include/logger_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../routing/include/event.hpp" +#include "../../service_discovery/include/defines.hpp" +#include "../../utility/include/utility.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" + +namespace vsomeip_v3 { +namespace cfg { + +configuration_impl::configuration_impl(const std::string &_path) + : default_unicast_("local"), + is_loaded_(false), + is_logging_loaded_(false), + prefix_(VSOMEIP_PREFIX), + diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS), + diagnosis_mask_(0xFF00), + has_console_log_(true), + has_file_log_(false), + has_dlt_log_(false), + logfile_("/tmp/vsomeip.log"), + loglevel_(vsomeip_v3::logger::level_e::LL_INFO), + is_sd_enabled_(VSOMEIP_SD_DEFAULT_ENABLED), + sd_protocol_(VSOMEIP_SD_DEFAULT_PROTOCOL), + sd_multicast_(VSOMEIP_SD_DEFAULT_MULTICAST), + sd_port_(VSOMEIP_SD_DEFAULT_PORT), + sd_initial_delay_min_(VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MIN), + sd_initial_delay_max_(VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX), + sd_repetitions_base_delay_(VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY), + sd_repetitions_max_(VSOMEIP_SD_DEFAULT_REPETITIONS_MAX), + sd_ttl_(VSOMEIP_SD_DEFAULT_TTL), + sd_cyclic_offer_delay_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY), + sd_request_response_delay_(VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY), + sd_offer_debounce_time_(VSOMEIP_SD_DEFAULT_OFFER_DEBOUNCE_TIME), + sd_find_debounce_time_(VSOMEIP_SD_DEFAULT_FIND_DEBOUNCE_TIME), + max_configured_message_size_(0), + max_local_message_size_(0), + max_reliable_message_size_(0), + max_unreliable_message_size_(0), + buffer_shrink_threshold_(VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD), + trace_(std::make_shared<trace>()), + watchdog_(std::make_shared<watchdog>()), + log_version_(true), + log_version_interval_(10), + permissions_uds_(VSOMEIP_DEFAULT_UDS_PERMISSIONS), + network_("vsomeip"), + e2e_enabled_(false), + log_memory_(false), + log_memory_interval_(0), + log_status_(false), + log_status_interval_(0), + endpoint_queue_limit_external_(QUEUE_SIZE_UNLIMITED), + endpoint_queue_limit_local_(QUEUE_SIZE_UNLIMITED), + tcp_restart_aborts_max_(VSOMEIP_MAX_TCP_RESTART_ABORTS), + tcp_connect_time_max_(VSOMEIP_MAX_TCP_CONNECT_TIME), + has_issued_methods_warning_(false), + has_issued_clients_warning_(false), + udp_receive_buffer_size_(VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE), + npdu_default_debounce_requ_(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO), + npdu_default_debounce_resp_(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO), + npdu_default_max_retention_requ_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO), + npdu_default_max_retention_resp_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO), + shutdown_timeout_(VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT), + log_statistics_(true), + statistics_interval_(VSOMEIP_DEFAULT_STATISTICS_INTERVAL), + statistics_min_freq_(VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ), + statistics_max_messages_(VSOMEIP_DEFAULT_STATISTICS_MAX_MSG), + max_remote_subscribers_(VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS), + path_(_path), + is_security_enabled_(false), + is_security_external_(false), + is_security_audit_(false), + is_remote_access_allowed_(true) { + + policy_manager_ = std::make_shared<policy_manager_impl>(); + security_ = std::make_shared<security>(policy_manager_); + unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS); + netmask_ = netmask_.from_string(VSOMEIP_NETMASK); + for (auto i = 0; i < ET_MAX; i++) + is_configured_[i] = false; + +#ifdef _WIN32 + routing_.host_.unicast_ = boost::asio::ip::make_address("127.0.0.1"); + routing_.host_.port_ = 31490; + routing_.guests_.unicast_ = routing_.host_.unicast_; + routing_.guests_.ports_[{ ANY_UID, ANY_GID }].emplace(31492, 31999); +#endif +} + +configuration_impl::configuration_impl(const configuration_impl &_other) + : std::enable_shared_from_this<configuration_impl>(_other), + default_unicast_(_other.default_unicast_), + is_loaded_(_other.is_loaded_), + is_logging_loaded_(_other.is_logging_loaded_), + mandatory_(_other.mandatory_), + has_console_log_(_other.has_console_log_.load()), + has_file_log_(_other.has_file_log_.load()), + has_dlt_log_(_other.has_dlt_log_.load()), + max_configured_message_size_(_other.max_configured_message_size_), + max_local_message_size_(_other.max_local_message_size_), + max_reliable_message_size_(_other.max_reliable_message_size_), + max_unreliable_message_size_(_other.max_unreliable_message_size_), + buffer_shrink_threshold_(_other.buffer_shrink_threshold_), + permissions_uds_(VSOMEIP_DEFAULT_UDS_PERMISSIONS), + endpoint_queue_limit_external_(_other.endpoint_queue_limit_external_), + endpoint_queue_limit_local_(_other.endpoint_queue_limit_local_), + tcp_restart_aborts_max_(_other.tcp_restart_aborts_max_), + tcp_connect_time_max_(_other.tcp_connect_time_max_), + udp_receive_buffer_size_(_other.udp_receive_buffer_size_), + npdu_default_debounce_requ_(_other.npdu_default_debounce_requ_), + npdu_default_debounce_resp_(_other.npdu_default_debounce_resp_), + npdu_default_max_retention_requ_(_other.npdu_default_max_retention_requ_), + npdu_default_max_retention_resp_(_other.npdu_default_max_retention_resp_), + shutdown_timeout_(_other.shutdown_timeout_), + path_(_other.path_) { + + applications_.insert(_other.applications_.begin(), _other.applications_.end()); + client_identifiers_ = _other.client_identifiers_; + services_.insert(_other.services_.begin(), _other.services_.end()); + clients_ = _other.clients_; + + unicast_ = _other.unicast_; + netmask_ = _other.netmask_; + device_ = _other.device_; + diagnosis_ = _other.diagnosis_; + diagnosis_mask_ = _other.diagnosis_mask_; + + logfile_ = _other.logfile_; + + loglevel_ = _other.loglevel_; + + routing_ = _other.routing_; + + is_sd_enabled_ = _other.is_sd_enabled_; + sd_multicast_ = _other.sd_multicast_; + sd_port_ = _other.sd_port_; + sd_protocol_ = _other.sd_protocol_; + + sd_initial_delay_min_ = _other.sd_initial_delay_min_; + sd_initial_delay_max_ = _other.sd_initial_delay_max_; + sd_repetitions_base_delay_= _other.sd_repetitions_base_delay_; + sd_repetitions_max_ = _other.sd_repetitions_max_; + sd_ttl_ = _other.sd_ttl_; + sd_cyclic_offer_delay_= _other.sd_cyclic_offer_delay_; + sd_request_response_delay_= _other.sd_request_response_delay_; + sd_offer_debounce_time_ = _other.sd_offer_debounce_time_; + sd_find_debounce_time_ = _other.sd_find_debounce_time_; + + trace_ = std::make_shared<trace>(*_other.trace_.get()); + supported_selective_addresses = _other.supported_selective_addresses; + watchdog_ = std::make_shared<watchdog>(*_other.watchdog_.get()); + internal_service_ranges_ = _other.internal_service_ranges_; + log_version_ = _other.log_version_; + log_version_interval_ = _other.log_version_interval_; + + magic_cookies_.insert(_other.magic_cookies_.begin(), _other.magic_cookies_.end()); + message_sizes_ = _other.message_sizes_; + + for (auto i = 0; i < ET_MAX; i++) + is_configured_[i] = _other.is_configured_[i]; + + network_ = _other.network_; + configuration_path_ = _other.configuration_path_; + + e2e_enabled_ = _other.e2e_enabled_; + e2e_configuration_ = _other.e2e_configuration_; + + log_memory_ = _other.log_memory_; + log_memory_interval_ = _other.log_memory_interval_; + log_status_ = _other.log_status_; + log_status_interval_ = _other.log_status_interval_; + + ttl_factors_offers_ = _other.ttl_factors_offers_; + ttl_factors_subscriptions_ = _other.ttl_factors_subscriptions_; + + debounces_ = _other.debounces_; + endpoint_queue_limits_ = _other.endpoint_queue_limits_; + + sd_acceptance_rules_ = _other.sd_acceptance_rules_; + + has_issued_methods_warning_ = _other.has_issued_methods_warning_; + has_issued_clients_warning_ = _other.has_issued_clients_warning_; + + log_statistics_ = _other.log_statistics_; + statistics_interval_ = _other.statistics_interval_; + statistics_min_freq_ = _other.statistics_min_freq_; + statistics_max_messages_ = _other.statistics_max_messages_; + max_remote_subscribers_ = _other.max_remote_subscribers_; + + is_security_enabled_ = _other.is_security_enabled_.load(); + is_security_external_ = _other.is_security_external_.load(); + is_security_audit_ = _other.is_security_audit_.load(); + is_remote_access_allowed_ = _other.is_remote_access_allowed_.load(); +} + +configuration_impl::~configuration_impl() { +} + +bool configuration_impl::load(const std::string &_name) { + std::lock_guard<std::mutex> its_lock(mutex_); + if (is_loaded_) + return true; + + // Environment + char *its_env; + + // Predefine file / folder + std::string its_file(VSOMEIP_DEFAULT_CONFIGURATION_FILE); // configuration file + std::string its_folder(VSOMEIP_DEFAULT_CONFIGURATION_FOLDER); // configuration folder + + if (!path_.empty()) { + if (utility::is_file(path_)) { + its_file = path_; + its_folder = ""; + } else { + its_file = ""; + its_folder = path_; + } + } + + // Override with local file / folder (if existing) + std::string its_local_file(VSOMEIP_LOCAL_CONFIGURATION_FILE); + if (utility::is_file(its_local_file)) { + its_file = its_local_file; + } + + std::string its_local_folder(VSOMEIP_LOCAL_CONFIGURATION_FOLDER); + if (utility::is_folder(its_local_folder)) { + its_folder = its_local_folder; + } + + // Override with path from environment (if existing) + std::string its_named_configuration(VSOMEIP_ENV_CONFIGURATION); + its_named_configuration += "_" + _name; + + its_env = getenv(its_named_configuration.c_str()); + if (nullptr == its_env) + its_env = getenv(VSOMEIP_ENV_CONFIGURATION); + if (nullptr != its_env) { + if (utility::is_file(its_env)) { + its_file = its_env; + its_folder = ""; + } else if (utility::is_folder(its_env)) { + its_folder = its_env; + its_file = ""; + } + } + + std::set<std::string> its_input; + if (its_file != "") { + its_input.insert(its_file); + } + if (its_folder != "") { + its_input.insert(its_folder); +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // load security configuration files from UID_GID sub folder if existing + std::stringstream its_security_config_folder; + its_security_config_folder << its_folder << "/" << getuid() << "_" << getgid(); + if (utility::is_folder(its_security_config_folder.str())) { + its_input.insert(its_security_config_folder.str()); + } +#endif + } + + // Determine standard configuration file + its_env = getenv(VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES); + if (nullptr != its_env) { + std::string its_temp(its_env); + set_mandatory(its_temp); + } else { + set_mandatory(VSOMEIP_MANDATORY_CONFIGURATION_FILES); + } + + // Start reading + std::set<std::string> its_failed; + + std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); + std::vector<configuration_element> its_mandatory_elements; + std::vector<configuration_element> its_optional_elements; + + // Look for the standard configuration file + read_data(its_input, its_mandatory_elements, its_failed, true); + load_data(its_mandatory_elements, true, false); + + // If the configuration is incomplete, this is the routing manager configuration or + // the routing is yet unknown, read the full set of configuration files + if (its_mandatory_elements.empty() || _name == get_routing_host_name() + || "" == get_routing_host_name()) { + read_data(its_input, its_optional_elements, its_failed, false); + load_data(its_mandatory_elements, false, true); + load_data(its_optional_elements, true, true); + } + + // Dummy initialization; if logger configs were not found use default + if (!is_logging_loaded_) { + logger::logger_impl::init(shared_from_this()); + } + + // Tell, if reading of configuration file(s) failed. + // (This may file if the logger configuration is incomplete/missing). + for (const auto& f : its_failed) + VSOMEIP_WARNING << "Reading of configuration file \"" + << f << "\" failed. Configuration may be incomplete."; + + // set global unicast address for all services with magic cookies enabled + set_magic_cookies_unicast_address(); + + std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + + for (const auto& i : its_input) { + if (utility::is_file(i)) + VSOMEIP_INFO << "Using configuration file: \"" << i << "\"."; + + if (utility::is_folder(i)) + VSOMEIP_INFO << "Using configuration folder: \"" << i << "\"."; + } + + VSOMEIP_INFO << "Parsed vsomeip configuration in " + << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() + << "ms"; + + is_loaded_ = true; + return is_loaded_; +} + +#ifndef VSOMEIP_DISABLE_SECURITY +bool configuration_impl::lazy_load_security(const std::string &_client_host) { + bool result(false); + + std::string its_folder = policy_manager_->get_policy_extension_path(_client_host); + if (!its_folder.empty()) { + std::set<std::string> its_input; + std::set<std::string> its_failed; + std::vector<configuration_element> its_mandatory_elements; + + its_input.insert(its_folder); + // load security configuration files from UID_GID sub folder if existing + std::string its_security_config_folder = policy_manager_->get_security_config_folder(its_folder); + + if (!its_security_config_folder.empty()) + its_input.insert(its_security_config_folder); + + read_data(its_input, its_mandatory_elements, its_failed, true, true); + + for (const auto& e : its_mandatory_elements) { + policy_manager_->load(e, true); + } + + for (auto f : its_failed) + VSOMEIP_WARNING << __func__ << ": Reading of configuration file \"" + << f << "\" failed. Configuration may be incomplete."; + + result = (its_failed.empty() && !its_mandatory_elements.empty()); + if (result) + policy_manager_->set_is_policy_extension_loaded(_client_host, true); + } + + return result; +} +#endif // !VSOMEIP_DISABLE_SECURITY + +bool +configuration_impl::check_routing_credentials( + client_t _client, const vsomeip_sec_client_t *_sec_client) const { + + return (_client != get_id(routing_.host_.name_) || + VSOMEIP_SEC_OK == security_->authenticate_router(_sec_client)); +} + +bool configuration_impl::remote_offer_info_add(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = false; + if (!is_loaded_) { + VSOMEIP_ERROR << __func__ << " shall only be called after normal" + "configuration has been parsed"; + } else { + auto its_service = std::make_shared<service>(); + its_service->service_ = _service; + its_service->instance_ = _instance; + its_service->reliable_ = its_service->unreliable_ = ILLEGAL_PORT; + _reliable ? + its_service->reliable_ = _port : + its_service->unreliable_ = _port; + its_service->unicast_address_ = default_unicast_; + its_service->multicast_address_ = ""; + its_service->multicast_port_ = ILLEGAL_PORT; + its_service->protocol_ = "someip"; + + { + std::lock_guard<std::mutex> its_lock(services_mutex_); + bool updated(false); + auto found_service = services_.find(its_service->service_); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find(its_service->instance_); + if (found_instance != found_service->second.end()) { + VSOMEIP_INFO << "Updating remote configuration for service [" + << std::hex << std::setw(4) << std::setfill('0') + << its_service->service_ << "." << its_service->instance_ << "]"; + if (_reliable) { + found_instance->second->reliable_ = its_service->reliable_; + } else { + found_instance->second->unreliable_ = its_service->unreliable_; + } + updated = true; + } + } + if (!updated) { + services_[_service][_instance] = its_service; + VSOMEIP_INFO << "Added new remote configuration for service [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service->service_ << "." + << std::setw(4) << its_service->instance_ << "]"; + } + if (_magic_cookies_enabled) { + magic_cookies_[its_service->unicast_address_].insert(its_service->reliable_); + } + } + ret = true; + } + return ret; +} + +bool configuration_impl::remote_offer_info_remove(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool* _still_offered_remote) { + (void)_port; + (void)_magic_cookies_enabled; + bool ret = false; + if (!is_loaded_) { + VSOMEIP_ERROR << __func__ << " shall only be called after normal" + "configuration has been parsed"; + } else { + std::lock_guard<std::mutex> its_lock(services_mutex_); + auto found_service = services_.find(_service); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + VSOMEIP_INFO << "Removing remote configuration for service [" + << std::hex << std::setw(4) << std::setfill('0') + << _service << "." << _instance << "]"; + if (_reliable) { + found_instance->second->reliable_ = ILLEGAL_PORT; + // TODO delete from magic_cookies_map without overwriting + // configurations from other services offered on the same port + } else { + found_instance->second->unreliable_ = ILLEGAL_PORT; + } + *_still_offered_remote = ( + found_instance->second->unreliable_ != ILLEGAL_PORT || + found_instance->second->reliable_ != ILLEGAL_PORT); + ret = true; + } + } + } + return ret; +} + +void configuration_impl::read_data(const std::set<std::string> &_input, + std::vector<configuration_element> &_elements, std::set<std::string> &_failed, + bool _mandatory_only, bool _read_second_level) { + for (auto i : _input) { + if (utility::is_file(i)) { + load_policy_data(i, _elements, _failed, _mandatory_only); + } else if (utility::is_folder(i)) { + // Use the map to ensure the configuration files are read in + // the ascending order of their names. This allows to use + // specific configuration file names to overwrite generic + // (or generated) parts of the configuration. + std::map<std::string, bool> its_names; + boost::filesystem::path its_path(i); + for (auto j = boost::filesystem::directory_iterator(its_path); + j != boost::filesystem::directory_iterator(); + j++) { + if (!boost::filesystem::is_directory(j->path())) { + its_names[j->path().string()] = _mandatory_only; + } else if(_read_second_level) { + //_read_second_level to read the second level folders only after + // the start, without this the ECU block + std::string name = j->path().string() + "/vsomeip_security.json"; + if (utility::is_file(name)) + its_names[name] = true; + } + } + + for (const auto &n : its_names) + load_policy_data(n.first, _elements, _failed, n.second); + } + } +} + +void configuration_impl::load_policy_data(const std::string &_input, + std::vector<configuration_element> &_elements, std::set<std::string> &_failed, + bool _mandatory_only) { + if (is_mandatory(_input) == _mandatory_only) { +#ifndef VSOMEIP_DISABLE_SECURITY + if (policy_manager_->is_policy_extension(_input)) { + policy_manager_->set_policy_extension_base_path(_input); + } +#endif + boost::property_tree::ptree its_tree; + try { + boost::property_tree::json_parser::read_json(_input, its_tree); + _elements.push_back({ _input, its_tree }); + } + catch (boost::property_tree::json_parser_error&) { + _failed.insert(_input); + } + } +} + +bool configuration_impl::load_data(const std::vector<configuration_element> &_elements, + bool _load_mandatory, bool _load_optional) { + // Load logging configuration data + std::set<std::string> its_warnings; + + if (!is_logging_loaded_) { + for (const auto& e : _elements) + is_logging_loaded_ + = load_logging(e, its_warnings) || is_logging_loaded_; + + if (is_logging_loaded_) { + logger::logger_impl::init(shared_from_this()); + for (const auto& w : its_warnings) + VSOMEIP_WARNING << w; + } + } + + bool has_routing(false); + bool has_applications(false); + if (_load_mandatory) { + // Load mandatory configuration data + for (const auto& e : _elements) { + has_routing = load_routing(e) || has_routing; + has_applications = load_applications(e) || has_applications; + load_network(e); + load_diagnosis_address(e); + load_shutdown_timeout(e); + load_payload_sizes(e); + load_endpoint_queue_sizes(e); + load_tcp_restart_settings(e); + load_permissions(e); + load_security(e); + load_tracing(e); + load_udp_receive_buffer_size(e); + load_services(e); + } + } + + if (_load_optional) { + for (const auto& e : _elements) { + load_unicast_address(e); + load_netmask(e); + load_device(e); + load_service_discovery(e); + load_npdu_default_timings(e); + load_internal_services(e); + load_clients(e); + load_watchdog(e); + load_selective_broadcasts_support(e); + load_e2e(e); + load_debounce(e); + load_acceptances(e); + load_secure_services(e); + load_partitions(e); + load_routing_client_ports(e); + load_suppress_events(e); + } + } + + return is_logging_loaded_ && has_routing && has_applications; +} + +bool configuration_impl::load_logging( + const configuration_element &_element, std::set<std::string> &_warnings) { + try { + auto its_logging = _element.tree_.get_child("logging"); + for (auto i = its_logging.begin(); i != its_logging.end(); ++i) { + std::string its_key(i->first); + if (its_key == "console") { + if (is_configured_[ET_LOGGING_CONSOLE]) { + _warnings.insert("Multiple definitions for logging.console." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + #ifndef ANDROID + has_console_log_ = (its_value == "true"); + #else + has_console_log_ = true; + #endif + is_configured_[ET_LOGGING_CONSOLE] = true; + } + } else if (its_key == "file") { + if (is_configured_[ET_LOGGING_FILE]) { + _warnings.insert("Multiple definitions for logging.file." + " Ignoring definition from " + _element.name_); + } else { + for (auto j : i->second) { + std::string its_sub_key(j.first); + std::string its_sub_value(j.second.data()); + if (its_sub_key == "enable") { + has_file_log_ = (its_sub_value == "true"); + } else if (its_sub_key == "path") { + logfile_ = its_sub_value; + } + } + is_configured_[ET_LOGGING_FILE] = true; + } + } else if (its_key == "dlt") { + if (is_configured_[ET_LOGGING_DLT]) { + _warnings.insert("Multiple definitions for logging.dlt." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + has_dlt_log_ = (its_value == "true"); + is_configured_[ET_LOGGING_DLT] = true; + } + } else if (its_key == "level") { + if (is_configured_[ET_LOGGING_LEVEL]) { + _warnings.insert("Multiple definitions for logging.level." + " Ignoring definition from " + _element.name_); + } else { + std::string its_value(i->second.data()); + std::lock_guard<std::mutex> lock(mutex_loglevel_); + loglevel_ + = (its_value == "trace" ? + vsomeip_v3::logger::level_e::LL_VERBOSE : + (its_value == "debug" ? + vsomeip_v3::logger::level_e::LL_DEBUG : + (its_value == "info" ? + vsomeip_v3::logger::level_e::LL_INFO : + (its_value == "warning" ? + vsomeip_v3::logger::level_e::LL_WARNING : + (its_value == "error" ? + vsomeip_v3::logger::level_e::LL_ERROR : + (its_value == "fatal" ? + vsomeip_v3::logger::level_e::LL_FATAL : + vsomeip_v3::logger::level_e::LL_INFO)))))); + is_configured_[ET_LOGGING_LEVEL] = true; + } + } else if (its_key == "version") { + std::stringstream its_converter; + for (auto j : i->second) { + std::string its_sub_key(j.first); + std::string its_sub_value(j.second.data()); + if (its_sub_key == "enable") { + log_version_ = (its_sub_value == "true"); + } else if (its_sub_key == "interval") { + its_converter << std::dec << its_sub_value; + its_converter >> log_version_interval_; + } + } + } else if (its_key == "memory_log_interval") { + std::stringstream its_converter; + its_converter << std::dec << i->second.data(); + its_converter >> log_memory_interval_; + if (log_memory_interval_ > 0) { + log_memory_ = true; + } + } else if (its_key == "status_log_interval") { + std::stringstream its_converter; + its_converter << std::dec << i->second.data(); + its_converter >> log_status_interval_; + if (log_status_interval_ > 0) { + log_status_ = true; + } + } else if (its_key == "statistics") { + for (auto j : i->second) { + std::stringstream its_converter; + std::string its_sub_key(j.first); + std::string its_sub_value(j.second.data()); + if (its_sub_key == "interval") { + its_converter << std::dec << its_sub_value; + its_converter >> statistics_interval_; + if (statistics_interval_ > 0) { + log_statistics_ = true; + } + } else if (its_sub_key == "min-frequency") { + its_converter << std::dec << its_sub_value; + its_converter >> statistics_min_freq_; + } else if (its_sub_key == "max-messages") { + its_converter << std::dec << its_sub_value; + its_converter >> statistics_max_messages_; + } + } + } + } + } catch (...) { + return false; + } + return true; +} + +bool +configuration_impl::load_routing(const configuration_element &_element) { + try { + auto its_routing = _element.tree_.get_child("routing"); + if (is_configured_[ET_ROUTING]) { + VSOMEIP_WARNING << "Multiple definitions of routing." + << " Ignoring definition from " << _element.name_; + } else { + routing_.is_enabled_ = + its_routing.get_optional<bool>("enabled").get_value_or(routing_.is_enabled_); + + bool is_loaded = load_routing_host(its_routing, _element.name_) + && load_routing_guests(its_routing); + + if (!is_loaded) { + routing_.host_.name_ = its_routing.data(); + } else { + if (routing_.guests_.unicast_.is_unspecified()) + routing_.guests_.unicast_ = routing_.host_.unicast_; + if (routing_.guests_.ports_.empty()) + routing_.guests_.ports_[{ ANY_UID, ANY_GID }].emplace(31492, 31999); + } + + // Try to validate the port configuration. Check whether a range + // contains an even number of ports and whether its starting port + // number fits to the configured routing host port. Correct both + // cases by reducing the range, if necessary. + std::set<std::pair<port_t, port_t> > its_invalid_ranges; + std::set<std::pair<port_t, port_t> > its_corrected_ranges; + for (auto &ug : routing_.guests_.ports_) { + for (auto &r : ug.second) { + auto its_pair = std::make_pair(r.first, r.second); + + bool is_even(((r.second - r.first + 1) % 2) == 0); + + // If the routing host port is [un]even, the start number of the + // range shall also be [un]even. + bool is_matching((r.first % 2) == (routing_.host_.port_ % 2)); + if (!is_matching) { + its_pair.first++; + if (is_even) + its_pair.second--; + } else if (!is_even) { + its_pair.second--; + } + + if (!is_even || !is_matching) { + its_invalid_ranges.insert(r); + its_corrected_ranges.insert(its_pair); + } + } + + for (const auto &r : its_invalid_ranges) + ug.second.erase(r); + its_invalid_ranges.clear(); + + for (const auto &r : its_corrected_ranges) + ug.second.insert(r); + its_corrected_ranges.clear(); + } + is_configured_[ET_ROUTING] = true; + } + } catch (...) { + return false; + } + return true; +} + +bool +configuration_impl::load_routing_host(const boost::property_tree::ptree &_tree, + const std::string &_name) { + + try { + bool has_uid(false), has_gid(false); + uid_t its_uid; + gid_t its_gid; + auto its_host = _tree.get_child("host"); + for (auto i = its_host.begin(); i != its_host.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + if (its_key == "name") { + routing_.host_.name_ = its_value; + } else if (its_key == "uid" || its_key == "gid") { + std::stringstream its_converter; + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + if (its_key == "uid") { + its_converter >> its_uid; + has_uid = true; + } else { + its_converter >> its_gid; + has_gid = true; + } + } else if (its_key == "unicast") { + routing_.host_.unicast_ + = boost::asio::ip::make_address(its_value); + } else if (its_key == "port") { + std::stringstream its_converter; + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> routing_.host_.port_; + } + } + + if (has_uid && has_gid) { + policy_manager_->set_routing_credentials(its_uid, its_gid, _name); + } + + } catch (...) { + return false; + } + return true; +} + +bool +configuration_impl::load_routing_guests(const boost::property_tree::ptree &_tree) { + + try { + auto its_guests = _tree.get_child("guests"); + for (auto i = its_guests.begin(); i != its_guests.end(); ++i) { + std::string its_key(i->first); + if (its_key == "unicast") { + std::string its_value(i->second.data()); + routing_.guests_.unicast_ + = boost::asio::ip::make_address(its_value); + } else if (its_key == "ports") { + load_routing_guest_ports(i->second); + } + } + } catch (...) { + // intentionally left empty + } + return true; +} + +void +configuration_impl::load_routing_guest_ports( + const boost::property_tree::ptree &_tree) { + + std::stringstream its_converter; + + for (auto its_range = _tree.begin(); + its_range != _tree.end(); ++its_range) { + + uid_t its_uid { ANY_UID }; + gid_t its_gid { ANY_GID }; + std::set<std::pair<port_t, port_t> > its_ranges; + + try { + auto its_uid_value = its_range->second.get_child("uid").data(); + its_converter.str(""); + its_converter.clear(); + its_converter << its_uid_value; + its_converter >> (its_uid_value.find("0x") == 0 ? std::hex : std::dec) >> its_uid; + + auto its_gid_value = its_range->second.get_child("gid").data(); + its_converter.str(""); + its_converter.clear(); + its_converter << its_gid_value; + its_converter >> (its_gid_value.find("0x") == 0 ? std::hex : std::dec) >> its_gid; + + auto its_ranges_value = its_range->second.get_child("ranges"); + its_ranges = load_routing_guest_port_range(its_ranges_value); + } catch (...) { + its_ranges = load_routing_guest_port_range(its_range->second); + } + + if (!its_ranges.empty()) + routing_.guests_.ports_[{ its_uid, its_gid }] = its_ranges; + } +} + +std::set< std::pair<port_t, port_t> > +configuration_impl::load_routing_guest_port_range( + const boost::property_tree::ptree &_tree) const { + + std::stringstream its_converter; + std::set< std::pair<port_t, port_t> > its_ranges; + + for (auto its_range = _tree.begin(); + its_range != _tree.end(); ++its_range) { + + port_t its_first_port { 0 }; + port_t its_last_port { 0 }; + + for (auto its_element = its_range->second.begin(); + its_element != its_range->second.end(); ++its_element) { + + std::string its_key(its_element->first); + std::string its_value(its_element->second.data()); + + if (!its_value.empty()) { + its_converter.str(""); + its_converter.clear(); + its_converter << (its_value.find("0x") == 0 ? std::hex : std::dec) << its_value; + + if (its_key == "first") { + its_converter >> its_first_port; + } else if (its_key == "last") { + its_converter >> its_last_port; + } + } + } + + if (its_first_port > 0 && its_last_port > 0) + its_ranges.emplace(std::min(its_first_port, its_last_port), + std::max(its_first_port, its_last_port)); + } + + return its_ranges; +} + +void +configuration_impl::load_routing_client_ports(const configuration_element &_element) { + + try { + auto its_ports = _element.tree_.get_child("routing-client-ports"); + load_routing_guest_ports(its_ports); + } + catch (...) { + } +} + +bool +configuration_impl::load_applications(const configuration_element &_element) { + try { + auto its_applications = _element.tree_.get_child("applications"); + for (auto i = its_applications.begin(); + i != its_applications.end(); + ++i) { + load_application_data(i->second, _element.name_); + } + } catch (...) { + return false; + } + return true; +} + +void configuration_impl::load_application_data( + const boost::property_tree::ptree &_tree, const std::string &_file_name) { + std::string its_name(""); + client_t its_id(VSOMEIP_CLIENT_UNSET); + std::size_t its_max_dispatchers(VSOMEIP_MAX_DISPATCHERS); + std::size_t its_max_dispatch_time(VSOMEIP_MAX_DISPATCH_TIME); + std::size_t its_max_detached_thread_wait_time(VSOMEIP_MAX_WAIT_TIME_DETACHED_THREADS); + std::size_t its_io_thread_count(VSOMEIP_DEFAULT_IO_THREAD_COUNT); + std::size_t its_request_debounce_time(VSOMEIP_REQUEST_DEBOUNCE_TIME); + std::map<plugin_type_e, std::set<std::string>> plugins; + int its_io_thread_nice_level(VSOMEIP_DEFAULT_IO_THREAD_NICE_LEVEL); + debounce_configuration_t its_debounces; + bool has_session_handling(true); + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "name") { + its_name = its_value; + } else if (its_key == "id") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_id; + } else if (its_key == "max_dispatchers") { + its_converter << std::dec << its_value; + its_converter >> its_max_dispatchers; + } else if (its_key == "max_dispatch_time") { + its_converter << std::dec << its_value; + its_converter >> its_max_dispatch_time; + } else if (its_key == "max_detached_thread_wait_time") { + its_converter << std::dec << its_value; + its_converter >> its_max_detached_thread_wait_time; + } else if (its_key == "threads") { + its_converter << std::dec << its_value; + its_converter >> its_io_thread_count; + if (its_io_thread_count == 0) { + VSOMEIP_WARNING << "Min. number of threads per application is 1"; + its_io_thread_count = 1; + } else if (its_io_thread_count > 255) { + VSOMEIP_WARNING << "Max. number of threads per application is 255"; + its_io_thread_count = 255; + } + } else if (its_key == "io_thread_nice") { + its_converter << std::dec << its_value; + its_converter >> its_io_thread_nice_level; + } else if (its_key == "request_debounce_time") { + its_converter << std::dec << its_value; + its_converter >> its_request_debounce_time; + if (its_request_debounce_time > 10000) { + VSOMEIP_WARNING << "Max. request debounce time is 10.000ms"; + its_request_debounce_time = 10000; + } + } else if (its_key == "plugins") { + plugins = load_plugins(i->second, its_name); + } else if (its_key == "debounce") { + try { + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + load_service_debounce(j->second, its_debounces); + } + } catch (...) { + // intentionally empty + } + } else if (its_key == "has_session_handling") { + has_session_handling = (its_value != "false"); + } + } + if (its_name != "") { + if (applications_.find(its_name) == applications_.end()) { + if (its_id != VSOMEIP_CLIENT_UNSET) { + if (!is_configured_client_id(its_id)) { + client_identifiers_.insert(its_id); + } else { + VSOMEIP_ERROR << "Multiple applications are configured to use" + << " client identifier " << std::hex << its_id + << ". Ignoring the configuration for application " + << its_name; + its_id = VSOMEIP_CLIENT_UNSET; + } + } + + applications_[its_name] = {its_id, + its_max_dispatchers, + its_max_dispatch_time, + its_max_detached_thread_wait_time, + its_io_thread_count, + its_request_debounce_time, + plugins, + its_io_thread_nice_level, + its_debounces, + has_session_handling}; + } else { + VSOMEIP_WARNING << "Multiple configurations for application " + << its_name << ". Ignoring a configuration from " + << _file_name; + } + } +} + +std::map<plugin_type_e, std::set<std::string>> configuration_impl::load_plugins( + const boost::property_tree::ptree &_tree, + const std::string &_application_name) { + std::map<plugin_type_e, std::set<std::string>> its_plugins; + std::string its_name(""); + std::string its_type; + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + bool its_configured[ET_MAX] = { 0 }; + for (auto l = i->second.begin(); l != i->second.end(); ++l) { + std::string its_inner_key(l->first); + std::string its_inner_value(l->second.data()); + + if (its_inner_key == "name") { + if (its_configured[ET_PLUGIN_NAME]) { + VSOMEIP_WARNING << "Multiple definitions of plugins.name." + << " Ignoring definition from " << its_inner_value; + } else { + its_name = its_inner_value; + its_configured[ET_PLUGIN_NAME] = true; + } + } else if (its_inner_key == "type") { + if (its_configured[ET_PLUGIN_TYPE]) { + VSOMEIP_WARNING << "Multiple definitions of plugins.type." + << " Ignoring definition from " << its_inner_value; + } else { + its_type = its_inner_value; + its_configured[ET_PLUGIN_TYPE] = true; + } + } else if (its_inner_key == "additional") { + if (its_configured[ET_PLUGIN_NAME]) { + const boost::property_tree::ptree &its_additional_tree(l->second); + for (auto m = its_additional_tree.begin(); m!= its_additional_tree.end(); ++m) { + for (auto n = m->second.begin(); n != m->second.end(); ++n) { + std::string its_additional_inner_key(n->first); + std::string its_additional_inner_value(n->second.data()); + plugins_additional_[_application_name][its_name] + [its_additional_inner_key] = + its_additional_inner_value; + } + } + } + } else { + //support old config format (type : name) + plugin_config_data_t its_plugin_data = { + its_inner_value, its_inner_key }; + add_plugin(its_plugins, its_plugin_data, _application_name); + } + } + + if (its_configured[ET_PLUGIN_NAME] && its_configured[ET_PLUGIN_TYPE]) { + plugin_config_data_t its_plugin_data = { + its_name, its_type }; + add_plugin(its_plugins, its_plugin_data, _application_name); + } + } + + return its_plugins; +} + +void configuration_impl::add_plugin(std::map<plugin_type_e, std::set<std::string>> &_plugins, + const plugin_config_data_t &_plugin_data, + const std::string& _application_name) { + +#ifdef _WIN32 + std::string its_library(_plugin_data.name_); + its_library += ".dll"; +#else + std::string its_library("lib"); + its_library += _plugin_data.name_; + its_library += ".so"; +#endif + + if (_plugin_data.type_ == "application_plugin") { +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + its_library += "."; + its_library += (VSOMEIP_APPLICATION_PLUGIN_VERSION + '0'); +#endif + _plugins[plugin_type_e::APPLICATION_PLUGIN].insert(its_library); + } else if (_plugin_data.type_ == "configuration_plugin") { +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + its_library += "."; + its_library += (VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION + '0'); +#endif + _plugins[plugin_type_e::PRE_CONFIGURATION_PLUGIN].insert(its_library); + } else { + VSOMEIP_WARNING << "Unknown plug-in type (" + << _plugin_data.type_ << ") configured for client: " + << _application_name; + } +} + +void configuration_impl::load_tracing(const configuration_element &_element) { + try { + auto its_trace_configuration = _element.tree_.get_child("tracing"); + for(auto i = its_trace_configuration.begin(); + i != its_trace_configuration.end(); + ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + if(its_key == "enable") { + if (is_configured_[ET_TRACING_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions of tracing.enable." + << " Ignoring definition from " << _element.name_; + } else { + trace_->is_enabled_ = (its_value == "true"); + is_configured_[ET_TRACING_ENABLE] = true; + } + } else if (its_key == "sd_enable") { + if (is_configured_[ET_TRACING_SD_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions of tracing.sd_enable." + << " Ignoring definition from " << _element.name_; + } else { + trace_->is_sd_enabled_ = (its_value == "true"); + is_configured_[ET_TRACING_SD_ENABLE] = true; + } + } else if(its_key == "channels") { + load_trace_channels(i->second); + } else if(its_key == "filters") { + load_trace_filters(i->second); + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_trace_channels( + const boost::property_tree::ptree &_tree) { + try { + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + if(i == _tree.begin()) + trace_->channels_.clear(); + load_trace_channel(i->second); + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_trace_channel( + const boost::property_tree::ptree &_tree) { + auto its_channel = std::make_shared<trace_channel>(); + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key = i->first; + std::string its_value = i->second.data(); + if(its_key == "name") { + its_channel->name_ = its_value; + } else if(its_key == "id") { + its_channel->id_ = its_value; + } + } + trace_->channels_.push_back(its_channel); +} + +void configuration_impl::load_trace_filters( + const boost::property_tree::ptree &_tree) { + try { + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + load_trace_filter(i->second); + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_trace_filter( + const boost::property_tree::ptree &_tree) { + auto its_filter = std::make_shared<trace_filter>(); + bool has_channel(false); + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key = i->first; + if (its_key == "channel") { + std::string its_value; + if (i->second.size() == 0) { + its_value = i->second.data(); + its_filter->channels_.push_back(its_value); + } else { + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + its_filter->channels_.push_back(j->second.data()); + } + } + has_channel = true; + } else if(its_key == "type") { + std::string its_value = i->second.data(); + if (its_value == "negative") + its_filter->ftype_ = vsomeip_v3::trace::filter_type_e::NEGATIVE; + else if (its_value == "header-only") + its_filter->ftype_ = vsomeip_v3::trace::filter_type_e::HEADER_ONLY; + else + its_filter->ftype_ = vsomeip_v3::trace::filter_type_e::POSITIVE; + } else { + load_trace_filter_expressions(i->second, its_key, its_filter); + } + } + + if (!has_channel) { + its_filter->channels_.push_back("TC"); // default + } + + if (!its_filter->is_range_ || its_filter->matches_.size() > 0) { + trace_->filters_.push_back(its_filter); + } +} + +void configuration_impl::load_trace_filter_expressions( + const boost::property_tree::ptree &_tree, + std::string &_criteria, + std::shared_ptr<trace_filter> &_filter) { + if (_criteria == "services") { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + vsomeip_v3::trace::match_t its_match; + load_trace_filter_match(i->second, its_match); + _filter->matches_.push_back(its_match); + } + } else if (_criteria == "methods") { + if (!has_issued_methods_warning_) { + VSOMEIP_WARNING << "\"method\" entry in filter configuration has no effect!"; + has_issued_methods_warning_ = true; + } + } else if (_criteria == "clients") { + if (!has_issued_clients_warning_) { + VSOMEIP_WARNING << "\"clients\" entry in filter configuration has no effect!"; + has_issued_clients_warning_ = true; + } + } else if (_criteria == "matches") { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + vsomeip_v3::trace::match_t its_match; + load_trace_filter_match(i->second, its_match); + if (i->first == "from") { + _filter->is_range_ = true; + _filter->matches_.insert(_filter->matches_.begin(), its_match); + } else { + if (i->first == "to") _filter->is_range_ = true; + _filter->matches_.push_back(its_match); + } + } + } +} + +void configuration_impl::load_trace_filter_match( + const boost::property_tree::ptree &_data, + vsomeip_v3::trace::match_t &_match) { + std::stringstream its_converter; + + if (_data.size() == 0) { + const std::string& its_value(_data.data()); + service_t its_service(ANY_SERVICE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_service; + + std::get<0>(_match) = its_service; + std::get<1>(_match) = ANY_INSTANCE; + std::get<2>(_match) = ANY_METHOD; + } else { + std::get<0>(_match) = ANY_SERVICE; + std::get<1>(_match) = ANY_INSTANCE; + std::get<2>(_match) = ANY_METHOD; + + for (auto i = _data.begin(); i != _data.end(); ++i) { + std::string its_value; + + its_converter.str(""); + its_converter.clear(); + + try { + its_value = i->second.data(); + if (its_value == "any") its_value = "0xffff"; + + if (i->first == "service") { + service_t its_service(ANY_SERVICE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_service; + std::get<0>(_match) = its_service; + } else if (i->first == "instance") { + instance_t its_instance(ANY_INSTANCE); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_instance; + std::get<1>(_match) = its_instance; + } else if (i->first == "method") { + method_t its_method(ANY_METHOD); + if (its_value.find("0x") == 0) { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_method; + std::get<2>(_match) = its_method; + } + } catch (...) { + // Intentionally left empty + } + } + } +} + +void configuration_impl::load_suppress_events(const configuration_element &_element) { + try { + auto its_missing_events = _element.tree_.get_child("suppress_missing_event_logs"); + + if(its_missing_events.size()) { + for (auto i = its_missing_events.begin(); + i != its_missing_events.end(); + ++i) { + load_suppress_events_data(i->second); + } + + if(suppress_events_.size()) + is_suppress_events_enabled_ = true; + } + } catch (...) { + // Intentionally left empty + } +} + +void configuration_impl::load_suppress_events_data( + const boost::property_tree::ptree &_tree) { + + //Default everything to ANY, and change with the provided values + service_t its_service(ANY_SERVICE); + instance_t its_instance(ANY_INSTANCE); + event_t its_event(ANY_EVENT); + std::set<event_t> events; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "service") { + its_service = load_suppress_data(its_value); + } else if (its_key == "instance") { + its_instance = load_suppress_data(its_value); + } else if (its_key == "events") { + if (i->second.empty()) { //Single Event + its_event = load_suppress_data(its_value); + events.insert(its_event); + } else { //Multiple Events/Range + events = load_suppress_multiple_events(i->second); + } + } + } + + //If no event is present in the configuration, use ANY_EVENT! + if(events.empty()) + events.insert(ANY_EVENT); + + for(const auto& event : events) { + insert_suppress_events(its_service, its_instance, event); + } +} + +std::set<event_t> configuration_impl::load_suppress_multiple_events( + const boost::property_tree::ptree &_tree) { + + event_t its_first_event(ANY_EVENT); + event_t its_last_event(ANY_EVENT); + event_t its_event(ANY_EVENT); + std::set<event_t> events; + + try { + for(auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + + //Extract Single Event from multiple entries + if (i->second.size() == 0) { + + if (its_key == "first") { // Range Events + its_first_event = load_suppress_data(its_value); + } else if (its_key == "last") { + its_last_event = load_suppress_data(its_value); + + std::set<event_t> range_events = load_range_events(its_first_event, its_last_event); + events.insert(range_events.begin(), range_events.end()); + return events; + } else { + //Single Events + its_event = load_suppress_data(its_value); + events.insert(its_event); + } + } else { + //Go down one level in the JSON, recursively + std::set<event_t> range_events = load_suppress_multiple_events(i->second); + events.insert(range_events.begin(), range_events.end()); + } + } + } catch (...) { + // intentionally left empty + } + return events; +} + +uint16_t configuration_impl::load_suppress_data(const std::string &_value) const { + + std::stringstream its_converter; + uint16_t its_converted = ANY_EVENT; + + if (_value == "any") { + its_converted = ANY_EVENT; //use ANY_x + } else if (_value.find("0x") == 0) { + its_converter << std::hex << _value; + } else { + its_converter << std::dec << _value; + } + its_converter >> its_converted; + + return its_converted; +} + +std::set<event_t> configuration_impl::load_range_events(event_t _first_event, + event_t _last_event) const { + + std::set<event_t> range_events; + + if ((_first_event != ANY_EVENT) && (_last_event != ANY_EVENT)) { + for (event_t its_event = _first_event; its_event<=_last_event; its_event++) { + range_events.insert(its_event); + } + } + return range_events; +} + +void configuration_impl::insert_suppress_events(service_t _service, + instance_t _instance, event_t _event) { + + suppress_t new_event = {_service, _instance, _event}; + suppress_events_.insert(new_event); +} + +bool configuration_impl::check_suppress_events(service_t _service, instance_t _instance, + event_t _event) const { + + if (!is_suppress_events_enabled_) + return false; + + std::set<suppress_t> event_combinations = { + {_service, _instance, _event}, + {_service, _instance, ANY_EVENT}, + {_service, ANY_INSTANCE, _event}, + {_service, ANY_INSTANCE, ANY_EVENT}, + {ANY_SERVICE, _instance, _event}, + {ANY_SERVICE, _instance, ANY_EVENT}, + {ANY_SERVICE, ANY_INSTANCE, _event} + }; + + for (const auto &its_event: event_combinations) { + if (suppress_events_.find(its_event) != std::end(suppress_events_)) + return true; + } + + return false; +} + +void configuration_impl::print_suppress_events(void) const { + + VSOMEIP_INFO << "Suppress Event logs size: " << suppress_events_.size(); + + for (const auto& its_log : suppress_events_) { + VSOMEIP_INFO << std::hex << std::setfill('0') + << "+[" << std::setw(4) << its_log.service + << "." << std::setw(4) << its_log.instance + << "." << its_log.event << "]"; + } +} + +void configuration_impl::load_unicast_address(const configuration_element &_element) { + try { + std::string its_value = _element.tree_.get<std::string>("unicast"); + if (is_configured_[ET_UNICAST]) { + VSOMEIP_WARNING << "Multiple definitions for unicast." + "Ignoring definition from " << _element.name_; + } else { + unicast_ = unicast_.from_string(its_value); + is_configured_[ET_UNICAST] = true; + } + } catch (...) { + // intentionally left empty! + } +} + +void configuration_impl::load_netmask(const configuration_element &_element) { + try { + auto its_value = _element.tree_.get_optional<std::string>("netmask"); + if (its_value) { + if (is_configured_[ET_NETMASK]) { + VSOMEIP_WARNING << "Multiple definitions for netmask/prefix." + "Ignoring netmask definition from " << _element.name_; + } else { + netmask_ = netmask_.from_string(*its_value); + is_configured_[ET_NETMASK] = true; + } + } + + its_value = _element.tree_.get_optional<std::string>("prefix"); + if (its_value) { + if (is_configured_[ET_NETMASK]) { + VSOMEIP_WARNING << "Multiple definitions for prefix/netmask." + "Ignoring prefix definition from " << _element.name_; + } else { + std::stringstream its_converter; + its_converter << *its_value; + its_converter >> std::dec >> prefix_; + + // Convert to netmask as this is used for IPv4. + uint32_t its_netmask = (std::numeric_limits<uint32_t>::max() + << (std::numeric_limits<uint32_t>::digits - prefix_)) + & std::numeric_limits<uint32_t>::max(); + netmask_ = boost::asio::ip::address_v4(its_netmask); + + is_configured_[ET_NETMASK] = true; + } + } + } catch (...) { + // intentionally left empty! + } +} + +void configuration_impl::load_device(const configuration_element &_element) { + try { + std::string its_value = _element.tree_.get<std::string>("device"); + if (is_configured_[ET_DEVICE]) { + VSOMEIP_WARNING << "Multiple definitions for device." + "Ignoring definition from " << _element.name_; + } else { + device_ = its_value; + is_configured_[ET_DEVICE] = true; + } + } catch (...) { + // intentionally left empty! + } +} + +void configuration_impl::load_network(const configuration_element &_element) { + try { + std::string its_value(_element.tree_.get<std::string>("network")); + if (is_configured_[ET_NETWORK]) { + VSOMEIP_WARNING << "Multiple definitions for network." + "Ignoring definition from " << _element.name_; + } else { + network_ = its_value; + is_configured_[ET_NETWORK] = true; + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_diagnosis_address(const configuration_element &_element) { + try { + std::string its_value = _element.tree_.get<std::string>("diagnosis"); + if (is_configured_[ET_DIAGNOSIS]) { + VSOMEIP_WARNING << "Multiple definitions for diagnosis." + "Ignoring definition from " << _element.name_; + } else { + std::stringstream its_converter; + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> diagnosis_; + is_configured_[ET_DIAGNOSIS] = true; + } + std::string its_mask = _element.tree_.get<std::string>("diagnosis_mask"); + if (is_configured_[ET_DIAGNOSIS_MASK]) { + VSOMEIP_WARNING << "Multiple definitions for diagnosis_mask." + "Ignoring definition from " << _element.name_; + } else { + std::stringstream its_converter; + + if (its_mask.size() > 1 && its_mask[0] == '0' && its_mask[1] == 'x') { + its_converter << std::hex << its_mask; + } else { + its_converter << std::dec << its_mask; + } + its_converter >> diagnosis_mask_; + is_configured_[ET_DIAGNOSIS_MASK] = true; + } + if (is_configured_[ET_DIAGNOSIS] && is_configured_[ET_DIAGNOSIS_MASK] + && (static_cast<std::uint16_t>(diagnosis_ << 8) & diagnosis_mask_) + != static_cast<std::uint16_t>(diagnosis_ << 8)) { + VSOMEIP_WARNING << "Diagnosis mask masks bits of diagnosis prefix! " + "Client IDs will start at 0x" << std::hex << + (static_cast<std::uint16_t>(diagnosis_ << 8) & diagnosis_mask_) + << " not at 0x" << static_cast<std::uint16_t>(diagnosis_ << 8); + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_shutdown_timeout(const configuration_element &_element) { + const std::string shutdown_timeout("shutdown_timeout"); + try { + if (_element.tree_.get_child_optional(shutdown_timeout)) { + std::string its_value = _element.tree_.get<std::string>("shutdown_timeout"); + if (is_configured_[ET_SHUTDOWN_TIMEOUT]) { + VSOMEIP_WARNING << "Multiple definitions for shutdown_timeout." + "Ignoring definition from " << _element.name_; + } else { + std::stringstream its_converter; + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> shutdown_timeout_; + is_configured_[ET_SHUTDOWN_TIMEOUT] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_service_discovery( + const configuration_element &_element) { + try { + auto its_service_discovery = _element.tree_.get_child("service-discovery"); + for (auto i = its_service_discovery.begin(); + i != its_service_discovery.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "enable") { + if (is_configured_[ET_SERVICE_DISCOVERY_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.enabled." + " Ignoring definition from " << _element.name_; + } else { + is_sd_enabled_ = (its_value == "true"); + is_configured_[ET_SERVICE_DISCOVERY_ENABLE] = true; + } + } else if (its_key == "multicast") { + if (is_configured_[ET_SERVICE_DISCOVERY_MULTICAST]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.multicast." + " Ignoring definition from " << _element.name_; + } else { + sd_multicast_ = its_value; + is_configured_[ET_SERVICE_DISCOVERY_MULTICAST] = true; + } + } else if (its_key == "port") { + if (is_configured_[ET_SERVICE_DISCOVERY_PORT]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.port." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_port_; + if (!sd_port_) { + sd_port_ = VSOMEIP_SD_DEFAULT_PORT; + } else { + is_configured_[ET_SERVICE_DISCOVERY_PORT] = true; + } + } + } else if (its_key == "protocol") { + if (is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.protocol." + " Ignoring definition from " << _element.name_; + } else { + sd_protocol_ = its_value; + is_configured_[ET_SERVICE_DISCOVERY_PROTOCOL] = true; + } + } else if (its_key == "initial_delay_min") { + if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_min." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_initial_delay_min_; + is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MIN] = true; + } + } else if (its_key == "initial_delay_max") { + if (is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.initial_delay_max." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_initial_delay_max_; + is_configured_[ET_SERVICE_DISCOVERY_INITIAL_DELAY_MAX] = true; + } + } else if (its_key == "repetitions_base_delay") { + if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_base_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_repetitions_base_delay_; + is_configured_[ET_SERVICE_DISCOVERY_REPETITION_BASE_DELAY] = true; + } + } else if (its_key == "repetitions_max") { + if (is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.repetition_max." + " Ignoring definition from " << _element.name_; + } else { + int tmp; + its_converter << its_value; + its_converter >> tmp; + sd_repetitions_max_ = (tmp > std::numeric_limits<std::uint8_t>::max()) ? + std::numeric_limits<std::uint8_t>::max() : + static_cast<std::uint8_t>(tmp); + is_configured_[ET_SERVICE_DISCOVERY_REPETITION_MAX] = true; + } + } else if (its_key == "ttl") { + if (is_configured_[ET_SERVICE_DISCOVERY_TTL]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.ttl." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_ttl_; + // We do _not_ accept 0 as this would mean "STOP OFFER" + if (sd_ttl_ == 0) { + VSOMEIP_WARNING << "TTL=0 is not allowed. Using default (" + << std::dec << VSOMEIP_SD_DEFAULT_TTL << ")"; + sd_ttl_ = VSOMEIP_SD_DEFAULT_TTL; + } + else is_configured_[ET_SERVICE_DISCOVERY_TTL] = true; + } + } else if (its_key == "cyclic_offer_delay") { + if (is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.cyclic_offer_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_cyclic_offer_delay_; + is_configured_[ET_SERVICE_DISCOVERY_CYCLIC_OFFER_DELAY] = true; + } + } else if (its_key == "request_response_delay") { + if (is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.request_response_delay." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_request_response_delay_; + is_configured_[ET_SERVICE_DISCOVERY_REQUEST_RESPONSE_DELAY] = true; + } + } else if (its_key == "offer_debounce_time") { + if (is_configured_[ET_SERVICE_DISCOVERY_OFFER_DEBOUNCE_TIME]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.offer_debounce." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_offer_debounce_time_; + is_configured_[ET_SERVICE_DISCOVERY_OFFER_DEBOUNCE_TIME] = true; + } + } else if (its_key == "find_debounce_time") { + if (is_configured_[ET_SERVICE_DISCOVERY_FIND_DEBOUNCE_TIME]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.find_debounce." + " Ignoring definition from " << _element.name_; + } else { + its_converter << its_value; + its_converter >> sd_find_debounce_time_; + is_configured_[ET_SERVICE_DISCOVERY_FIND_DEBOUNCE_TIME] = true; + } + } else if (its_key == "ttl_factor_offers") { + if (is_configured_[ET_SERVICE_DISCOVERY_TTL_FACTOR_OFFERS]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.ttl_factor_offers." + " Ignoring definition from " << _element.name_; + } else { + load_ttl_factors(i->second, &ttl_factors_offers_); + is_configured_[ET_SERVICE_DISCOVERY_TTL_FACTOR_OFFERS] = true; + } + } else if (its_key == "ttl_factor_subscriptions") { + if (is_configured_[ET_SERVICE_DISCOVERY_TTL_FACTOR_SUBSCRIPTIONS]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.ttl_factor_subscriptions." + " Ignoring definition from " << _element.name_; + } else { + load_ttl_factors(i->second, &ttl_factors_subscriptions_); + is_configured_[ET_SERVICE_DISCOVERY_TTL_FACTOR_SUBSCRIPTIONS] = true; + } + } else if (its_key == "max_remote_subscribers") { + if (is_configured_[ET_MAX_REMOTE_SUBSCRIBERS]) { + VSOMEIP_WARNING << "Multiple definitions for service_discovery.max_remote_subscribers." + " Ignoring definition from " << _element.name_; + } else { + int tmp; + its_converter << its_value; + its_converter >> tmp; + max_remote_subscribers_ = (tmp > std::numeric_limits<std::uint8_t>::max()) ? + std::numeric_limits<std::uint8_t>::max() : + static_cast<std::uint8_t>(tmp); + if (max_remote_subscribers_ == 0) { + VSOMEIP_WARNING << "max_remote_subscribers_ = 0 is not allowed. Using default (" + << std::dec << VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS << ")"; + max_remote_subscribers_ = VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS; + } + is_configured_[ET_MAX_REMOTE_SUBSCRIBERS] = true; + } + } + } + } catch (...) { + } +} + +void configuration_impl::load_delays( + const boost::property_tree::ptree &_tree) { + try { + std::stringstream its_converter; + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + if (its_key == "initial") { + sd_initial_delay_min_ = i->second.get<uint32_t>("minimum"); + sd_initial_delay_max_ = i->second.get<uint32_t>("maximum"); + } else if (its_key == "repetition-base") { + its_converter << std::dec << i->second.data(); + its_converter >> sd_repetitions_base_delay_; + } else if (its_key == "repetition-max") { + int tmp_repetition_max; + its_converter << std::dec << i->second.data(); + its_converter >> tmp_repetition_max; + sd_repetitions_max_ = + (tmp_repetition_max + > std::numeric_limits<std::uint8_t>::max()) ? + std::numeric_limits<std::uint8_t>::max() : + static_cast<std::uint8_t>(tmp_repetition_max); + } else if (its_key == "cyclic-offer") { + its_converter << std::dec << i->second.data(); + its_converter >> sd_cyclic_offer_delay_; + } else if (its_key == "cyclic-request") { + its_converter << std::dec << i->second.data(); + its_converter >> sd_request_response_delay_; + } else if (its_key == "ttl") { + its_converter << std::dec << i->second.data(); + its_converter >> sd_ttl_; + } + its_converter.str(""); + its_converter.clear(); + } + } catch (...) { + } +} + +void configuration_impl::load_npdu_default_timings(const configuration_element &_element) { + const std::string ndt("npdu-default-timings"); + const std::string dreq("debounce-time-request"); + const std::string dres("debounce-time-response"); + const std::string rreq("max-retention-time-request"); + const std::string rresp("max-retention-time-response"); + try { + if (_element.tree_.get_child_optional(ndt)) { + if (is_configured_[ET_NPDU_DEFAULT_TIMINGS]) { + VSOMEIP_WARNING << "Multiple definitions of " << ndt + << " Ignoring definition from " << _element.name_; + } else { + for (const auto& e : _element.tree_.get_child(ndt)) { + std::chrono::nanoseconds its_time(0); + try { + its_time = std::chrono::nanoseconds( + std::strtoull(e.second.data().c_str(), NULL, 10) + * 1000000); + } catch (const std::exception&) { + continue; + } + if (e.first.data() == dreq) { + npdu_default_debounce_requ_ = its_time; + } else if (e.first.data() == dres) { + npdu_default_debounce_resp_ = its_time; + } else if (e.first.data() == rreq) { + npdu_default_max_retention_requ_ = its_time; + } else if (e.first.data() == rresp) { + npdu_default_max_retention_resp_ = its_time; + } + } + is_configured_[ET_NPDU_DEFAULT_TIMINGS] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_services(const configuration_element &_element) { + std::lock_guard<std::mutex> its_lock(services_mutex_); + try { + auto its_services = _element.tree_.get_child("services"); + for (auto i = its_services.begin(); i != its_services.end(); ++i) + load_service(i->second, default_unicast_); + } catch (...) { + try { + auto its_servicegroups = _element.tree_.get_child("servicegroups"); + for (auto i = its_servicegroups.begin(); i != its_servicegroups.end(); ++i) + load_servicegroup(i->second); + } catch (...) { + // intentionally left empty + } + } +} + +void configuration_impl::load_servicegroup( + const boost::property_tree::ptree &_tree) { + try { + std::string its_unicast_address(default_unicast_); + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + if (its_key == "unicast") { + its_unicast_address = i->second.data(); + break; + } + } + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + if (its_key == "delays") { + load_delays(i->second); + } else if (its_key == "services") { + for (auto j = i->second.begin(); j != i->second.end(); ++j) + load_service(j->second, its_unicast_address); + } + } + } catch (...) { + // Intentionally left empty + } +} + +void configuration_impl::load_service( + const boost::property_tree::ptree &_tree, + const std::string &_unicast_address) { + try { + bool is_loaded(true); + bool use_magic_cookies(false); + + auto its_service = std::make_shared<service>(); + its_service->reliable_ = its_service->unreliable_ = ILLEGAL_PORT; + its_service->unicast_address_ = _unicast_address; + its_service->multicast_address_ = ""; + its_service->multicast_port_ = ILLEGAL_PORT; + its_service->protocol_ = "someip"; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "unicast") { + its_service->unicast_address_ = its_value; + } else if (its_key == "reliable") { + try { + its_value = i->second.get_child("port").data(); + its_converter << its_value; + its_converter >> its_service->reliable_; + } catch (...) { + its_converter << its_value; + its_converter >> its_service->reliable_; + } + if(!its_service->reliable_) { + its_service->reliable_ = ILLEGAL_PORT; + } + try { + its_value + = i->second.get_child("enable-magic-cookies").data(); + use_magic_cookies = ("true" == its_value); + } catch (...) { + + } + } else if (its_key == "unreliable") { + its_converter << its_value; + its_converter >> its_service->unreliable_; + if(!its_service->unreliable_) { + its_service->unreliable_ = ILLEGAL_PORT; + } + } else if (its_key == "multicast") { + try { + its_value = i->second.get_child("address").data(); + its_service->multicast_address_ = its_value; + its_value = i->second.get_child("port").data(); + its_converter << its_value; + its_converter >> its_service->multicast_port_; + } catch (...) { + } + } else if (its_key == "protocol") { + its_service->protocol_ = its_value; + } else if (its_key == "events") { + load_event(its_service, i->second); + } else if (its_key == "eventgroups") { + load_eventgroup(its_service, i->second); + } else if (its_key == "debounce-times") { + load_npdu_debounce_times_configuration(its_service, i->second); + } else if (its_key == "someip-tp") { + load_someip_tp(its_service, i->second); + } else { + // Trim "its_value" + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "service") { + its_converter >> its_service->service_; + } else if (its_key == "instance") { + its_converter >> its_service->instance_; + } + } + } + + auto found_service = services_.find(its_service->service_); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find( + its_service->instance_); + if (found_instance != found_service->second.end()) { + VSOMEIP_WARNING << "Multiple configurations for service [" + << std::hex << its_service->service_ << "." + << its_service->instance_ << "]"; + is_loaded = false; + } + } + + if (is_loaded) { + services_[its_service->service_][its_service->instance_] = + its_service; + if (use_magic_cookies) { + magic_cookies_[its_service->unicast_address_].insert(its_service->reliable_); + } + + if (its_service->unicast_address_ == default_unicast_) { + // local services + if(its_service->reliable_ != ILLEGAL_PORT) { + services_by_ip_port_[unicast_.to_string()] + [its_service->reliable_] + [its_service->service_] = its_service; + } + if (its_service->unreliable_ != ILLEGAL_PORT) { + services_by_ip_port_[unicast_.to_string()] + [its_service->unreliable_] + [its_service->service_] = its_service; + // This is necessary as all udp server endpoints listen on + // INADDR_ANY instead of a specific address + services_by_ip_port_[boost::asio::ip::address_v4::any().to_string()] + [its_service->unreliable_] + [its_service->service_] = its_service; + services_by_ip_port_[boost::asio::ip::address_v6::any().to_string()] + [its_service->unreliable_] + [its_service->service_] = its_service; + } + } else { + // remote services + if (its_service->reliable_ != ILLEGAL_PORT) { + services_by_ip_port_[its_service->unicast_address_] + [its_service->reliable_] + [its_service->service_] = its_service; + } + if (its_service->unreliable_ != ILLEGAL_PORT) { + services_by_ip_port_[its_service->unicast_address_] + [its_service->unreliable_] + [its_service->service_] = its_service; + } + } + } + } catch (...) { + // Intentionally left empty + } +} + +void configuration_impl::load_event( + std::shared_ptr<service> &_service, + const boost::property_tree::ptree &_tree) { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + event_t its_event_id(0); + bool its_is_field(false); + reliability_type_e its_reliability(reliability_type_e::RT_UNKNOWN); + uint32_t its_cycle_value; + std::chrono::milliseconds its_cycle(std::chrono::milliseconds::zero()); + bool its_change_resets_cycle(false); + bool its_update_on_change(true); + + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "event") { + std::stringstream its_converter; + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_event_id; + } else if (its_key == "is_field") { + its_is_field = (its_value == "true"); + } else if (its_key == "is_reliable") { + if (its_value == "true") + its_reliability = reliability_type_e::RT_RELIABLE; + else + its_reliability = reliability_type_e::RT_UNRELIABLE; + } else if (its_key == "cycle") { + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> its_cycle_value; + its_cycle = std::chrono::milliseconds(its_cycle_value); + } else if (its_key == "change_resets_cycle") { + its_change_resets_cycle = (its_value == "true"); + } else if (its_key == "update_on_change") { + its_update_on_change = (its_value == "true"); + } + } + + if (its_event_id > 0) { + auto found_event = _service->events_.find(its_event_id); + if (found_event != _service->events_.end()) { + VSOMEIP_INFO << "Multiple configurations for event [" + << std::hex << _service->service_ << "." + << _service->instance_ << "." + << its_event_id << "]."; + } else { + // If event reliability type was not configured, + if (its_reliability == reliability_type_e::RT_UNKNOWN) { + if (_service->unreliable_ != ILLEGAL_PORT) { + its_reliability = reliability_type_e::RT_UNRELIABLE; + } else if (_service->reliable_ != ILLEGAL_PORT) { + its_reliability = reliability_type_e::RT_RELIABLE; + } + VSOMEIP_WARNING << "Reliability type for event [" + << std::hex << _service->service_ << "." + << _service->instance_ << "." + << its_event_id << "] was not configured Using : " + << ((its_reliability == reliability_type_e::RT_RELIABLE) + ? "RT_RELIABLE" : "RT_UNRELIABLE"); + } + + auto its_event = std::make_shared<event>( + its_event_id, its_is_field, its_reliability, + its_cycle, its_change_resets_cycle, + its_update_on_change); + _service->events_[its_event_id] = its_event; + } + } + } +} + +void configuration_impl::load_eventgroup( + std::shared_ptr<service> &_service, + const boost::property_tree::ptree &_tree) { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + auto its_eventgroup = + std::make_shared<eventgroup>(); + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::stringstream its_converter; + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "eventgroup") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_eventgroup->id_; + } else if (its_key == "is_multicast") { + std::string its_value(j->second.data()); + if (its_value == "true") { + its_eventgroup->multicast_address_ = _service->multicast_address_; + its_eventgroup->multicast_port_ = _service->multicast_port_; + } + } else if (its_key == "multicast") { + try { + std::string its_value = j->second.get_child("address").data(); + its_eventgroup->multicast_address_ = its_value; + its_value = j->second.get_child("port").data(); + its_converter << its_value; + its_converter >> its_eventgroup->multicast_port_; + } catch (...) { + } + } else if (its_key == "threshold") { + int its_threshold(0); + std::stringstream its_converter; + its_converter << std::dec << its_value; + its_converter >> std::dec >> its_threshold; + its_eventgroup->threshold_ = + (its_threshold > std::numeric_limits<std::uint8_t>::max()) ? + std::numeric_limits<std::uint8_t>::max() : + static_cast<uint8_t>(its_threshold); + } else if (its_key == "events") { + for (auto k = j->second.begin(); k != j->second.end(); ++k) { + std::stringstream its_converter; + std::string its_value(k->second.data()); + event_t its_event_id(0); + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_event_id; + if (0 < its_event_id) { + std::shared_ptr<event> its_event(nullptr); + auto find_event = _service->events_.find(its_event_id); + if (find_event != _service->events_.end()) { + its_event = find_event->second; + } else { + its_event = std::make_shared<event>(its_event_id, + false, reliability_type_e::RT_UNRELIABLE, + std::chrono::milliseconds::zero(), + false, true); + } + if (its_event) { + its_event->groups_.push_back(its_eventgroup); + its_eventgroup->events_.insert(its_event); + _service->events_[its_event_id] = its_event; + } + } + } + } + } + + if (its_eventgroup->id_ > 0) { + _service->eventgroups_[its_eventgroup->id_] = its_eventgroup; + } + } +} + +void configuration_impl::load_internal_services(const configuration_element &_element) { + try { + auto optional = _element.tree_.get_child_optional("internal_services"); + if (!optional) { + return; + } + auto its_internal_services = _element.tree_.get_child("internal_services"); + for (auto found_range = its_internal_services.begin(); + found_range != its_internal_services.end(); ++found_range) { + service_instance_range range; + range.first_service_ = 0x0; + range.last_service_ = 0x0; + range.first_instance_ = 0x0; + range.last_instance_ = 0xffff; + for (auto i = found_range->second.begin(); + i != found_range->second.end(); ++i) { + if (i->first == "first") { + if (i->second.size() == 0) { + std::stringstream its_converter; + std::string value = i->second.data(); + its_converter << std::hex << value; + its_converter >> range.first_service_; + } + for (auto n = i->second.begin(); + n != i->second.end(); ++n) { + if (n->first == "service") { + std::stringstream its_converter; + std::string value = n->second.data(); + its_converter << std::hex << value; + its_converter >> range.first_service_; + } else if (n->first == "instance") { + std::stringstream its_converter; + std::string value = n->second.data(); + its_converter << std::hex << value; + its_converter >> range.first_instance_; + } + } + } else if (i->first == "last") { + if (i->second.size() == 0) { + std::stringstream its_converter; + std::string value = i->second.data(); + its_converter << std::hex << value; + its_converter >> range.last_service_; + } + for (auto n = i->second.begin(); + n != i->second.end(); ++n) { + if (n->first == "service") { + std::stringstream its_converter; + std::string value = n->second.data(); + its_converter << std::hex << value; + its_converter >> range.last_service_; + } else if (n->first == "instance") { + std::stringstream its_converter; + std::string value = n->second.data(); + its_converter << std::hex << value; + its_converter >> range.last_instance_; + } + } + } + } + if (range.last_service_ >= range.first_service_) { + if (range.last_instance_ >= range.first_instance_) { + internal_service_ranges_.push_back(range); + } + } + } + } catch (...) { + VSOMEIP_ERROR << "Error parsing internal service range configuration!"; + } +} + +void configuration_impl::load_clients(const configuration_element &_element) { + try { + auto its_clients = _element.tree_.get_child("clients"); + for (auto i = its_clients.begin(); i != its_clients.end(); ++i) + load_client(i->second); + } catch (...) { + // intentionally left empty! + } +} + +void configuration_impl::load_client(const boost::property_tree::ptree &_tree) { + try { + auto its_client = std::make_shared<client>(); + its_client->remote_ports_[true] = std::make_pair(ILLEGAL_PORT, ILLEGAL_PORT); + its_client->remote_ports_[false] = std::make_pair(ILLEGAL_PORT, ILLEGAL_PORT); + its_client->client_ports_[true] = std::make_pair(ILLEGAL_PORT, ILLEGAL_PORT); + its_client->client_ports_[false] = std::make_pair(ILLEGAL_PORT, ILLEGAL_PORT); + its_client->last_used_specific_client_port_[true] = ILLEGAL_PORT; + its_client->last_used_specific_client_port_[false] = ILLEGAL_PORT; + its_client->last_used_client_port_[true] = ILLEGAL_PORT; + its_client->last_used_client_port_[false] = ILLEGAL_PORT; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "reliable_remote_ports") { + its_client->remote_ports_[true] = load_client_port_range(i->second); + } else if (its_key == "unreliable_remote_ports") { + its_client->remote_ports_[false] = load_client_port_range(i->second); + } else if (its_key == "reliable_client_ports") { + its_client->client_ports_[true] = load_client_port_range(i->second); + } else if (its_key == "unreliable_client_ports") { + its_client->client_ports_[false] = load_client_port_range(i->second); + } else if (its_key == "reliable") { + its_client->ports_[true] = load_client_ports(i->second); + } else if (its_key == "unreliable") { + its_client->ports_[false] = load_client_ports(i->second); + } else { + // Trim "its_value" + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "service") { + its_converter >> its_client->service_; + } else if (its_key == "instance") { + its_converter >> its_client->instance_; + } + } + } + clients_.push_back(its_client); + } catch (...) { + } +} + +std::set<uint16_t> configuration_impl::load_client_ports( + const boost::property_tree::ptree &_tree) { + std::set<uint16_t> its_ports; + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_value(i->second.data()); + uint16_t its_port_value; + + std::stringstream its_converter; + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_port_value; + its_ports.insert(its_port_value); + } + return its_ports; +} + +std::pair<uint16_t,uint16_t> configuration_impl::load_client_port_range( + const boost::property_tree::ptree &_tree) { + std::pair<uint16_t,uint16_t> its_port_range; + uint16_t its_first_port = ILLEGAL_PORT; + uint16_t its_last_port = ILLEGAL_PORT; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "first") { + its_converter >> its_first_port; + } else if (its_key == "last") { + its_converter >> its_last_port; + } + } + + if (its_last_port < its_first_port) { + VSOMEIP_WARNING << "Port range invalid: first: " << std::dec << its_first_port << " last: " << its_last_port; + its_port_range = std::make_pair(ILLEGAL_PORT, ILLEGAL_PORT); + } else { + its_port_range = std::make_pair(its_first_port, its_last_port); + } + + return its_port_range; +} + +void configuration_impl::load_watchdog(const configuration_element &_element) { + try { + auto its_service_discovery = _element.tree_.get_child("watchdog"); + for (auto i = its_service_discovery.begin(); + i != its_service_discovery.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + if (its_key == "enable") { + if (is_configured_[ET_WATCHDOG_ENABLE]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.enable." + " Ignoring definition from " << _element.name_; + } else { + watchdog_->is_enabeled_ = (its_value == "true"); + is_configured_[ET_WATCHDOG_ENABLE] = true; + } + } else if (its_key == "timeout") { + if (is_configured_[ET_WATCHDOG_TIMEOUT]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.timeout." + " Ignoring definition from " << _element.name_; + } else { + its_converter << std::dec << its_value; + its_converter >> watchdog_->timeout_in_ms_; + is_configured_[ET_WATCHDOG_TIMEOUT] = true; + } + } else if (its_key == "allowed_missing_pongs") { + if (is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS]) { + VSOMEIP_WARNING << "Multiple definitions of watchdog.allowed_missing_pongs." + " Ignoring definition from " << _element.name_; + } else { + its_converter << std::dec << its_value; + its_converter >> watchdog_->missing_pongs_allowed_; + is_configured_[ET_WATCHDOG_ALLOWED_MISSING_PONGS] = true; + } + } + } + } catch (...) { + } +} + +void configuration_impl::load_payload_sizes(const configuration_element &_element) { + const std::string payload_sizes("payload-sizes"); + const std::string max_local_payload_size("max-payload-size-local"); + const std::string buffer_shrink_threshold("buffer-shrink-threshold"); + const std::string max_reliable_payload_size("max-payload-size-reliable"); + const std::string max_unreliable_payload_size("max-payload-size-unreliable"); + try { + for (const auto& s : { max_local_payload_size, + max_reliable_payload_size, max_unreliable_payload_size }) { + if (_element.tree_.get_child_optional(s)) { + const std::string size_str(_element.tree_.get_child(s).data()); + try { + // add 16 Byte for the SOME/IP header + const auto its_size = static_cast<std::uint32_t>( + std::stoul(size_str.c_str(), NULL, 10) + 16); + if (s == max_local_payload_size) { + max_local_message_size_ = its_size; + } else if (s == max_reliable_payload_size) { + max_reliable_message_size_ = its_size; + } else if (s == max_unreliable_payload_size) { + max_unreliable_message_size_ = its_size; + } + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": " << s << " " << e.what(); + } + } + } + + if (_element.tree_.get_child_optional(buffer_shrink_threshold)) { + auto bst = _element.tree_.get_child(buffer_shrink_threshold); + std::string s(bst.data()); + try { + buffer_shrink_threshold_ = static_cast<std::uint32_t>( + std::stoul(s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": " << buffer_shrink_threshold + << " " << e.what(); + } + } + if (_element.tree_.get_child_optional(payload_sizes)) { + const std::string unicast("unicast"); + const std::string ports("ports"); + const std::string port("port"); + const std::string max_payload_size("max-payload-size"); + auto its_ps = _element.tree_.get_child(payload_sizes); + for (auto i = its_ps.begin(); i != its_ps.end(); ++i) { + if (!i->second.get_child_optional(unicast) + || !i->second.get_child_optional(ports)) { + continue; + } + std::string its_unicast(i->second.get_child(unicast).data()); + for (auto j = i->second.get_child(ports).begin(); + j != i->second.get_child(ports).end(); ++j) { + + if (!j->second.get_child_optional(port) + || !j->second.get_child_optional(max_payload_size)) { + continue; + } + + std::uint16_t its_port = ILLEGAL_PORT; + std::uint32_t its_message_size = 0; + + try { + std::string p(j->second.get_child(port).data()); + its_port = static_cast<std::uint16_t>(std::stoul(p.c_str(), + NULL, 10)); + std::string s(j->second.get_child(max_payload_size).data()); + // add 16 Byte for the SOME/IP header + its_message_size = static_cast<std::uint32_t>( + std::stoul(s.c_str(), NULL, 10) + 16); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << ":" << e.what(); + } + + if (its_port == ILLEGAL_PORT || its_message_size == 0) { + continue; + } + if (max_configured_message_size_ < its_message_size) { + max_configured_message_size_ = its_message_size; + } + + message_sizes_[its_unicast][its_port] = its_message_size; + } + } + if (max_local_message_size_ != 0 + && max_configured_message_size_ != 0 + && max_configured_message_size_ > max_local_message_size_) { + VSOMEIP_WARNING << max_local_payload_size + << " is configured smaller than the biggest payloadsize" + << " for external communication. " + << max_local_payload_size << " will be increased to " + << max_configured_message_size_ - 16 << " to ensure " + << "local message distribution."; + max_local_message_size_ = max_configured_message_size_; + } + if (max_local_message_size_ != 0 + && max_reliable_message_size_ != 0 + && max_reliable_message_size_ > max_local_message_size_) { + VSOMEIP_WARNING << max_local_payload_size << " (" + << max_local_message_size_ - 16 << ") is configured" + << " smaller than " << max_reliable_payload_size << " (" + << max_reliable_message_size_ - 16 << "). " + << max_local_payload_size << " will be increased to " + << max_reliable_message_size_ - 16 << " to ensure " + << "local message distribution."; + max_local_message_size_ = max_reliable_message_size_; + } + if (max_local_message_size_ != 0 + && max_unreliable_message_size_ != 0 + && max_unreliable_message_size_ > max_local_message_size_) { + VSOMEIP_WARNING << max_local_payload_size << " (" + << max_local_message_size_ - 16 << ") is configured" + << " smaller than " << max_unreliable_payload_size << " (" + << max_unreliable_message_size_ - 16 << "). " + << max_local_payload_size << " will be increased to " + << max_unreliable_message_size_ - 16 << " to ensure " + << "local message distribution."; + max_local_message_size_ = max_unreliable_message_size_; + } + } + } catch (...) { + } +} + +void configuration_impl::load_permissions(const configuration_element &_element) { + const std::string file_permissions("file-permissions"); + try { + if (_element.tree_.get_child_optional(file_permissions)) { + auto its_permissions = _element.tree_.get_child(file_permissions); + for (auto i = its_permissions.begin(); i != its_permissions.end(); + ++i) { + std::string its_key(i->first); + std::stringstream its_converter; + if (its_key == "permissions-uds") { + std::string its_value(i->second.data()); + its_converter << std::oct << its_value; + its_converter >> permissions_uds_; + + } + } + } + } catch (...) { + } +} + +void configuration_impl::load_security(const configuration_element &_element) { + + try { + auto its_security = _element.tree_.get_child_optional("security"); + if (its_security) { + is_security_enabled_ = true; + is_security_external_ = its_security->empty(); + + auto its_audit_mode = its_security->get_child_optional("check_credentials"); + if (its_audit_mode) { + if (is_configured_[ET_SECURITY_AUDIT_MODE]) { + VSOMEIP_WARNING << "Multiple definitions for security audit mode (" + << "(check_credentials). Ignoring definition from " + << _element.name_; + } else { + is_security_audit_ = (its_audit_mode->data() != "true"); + is_configured_[ET_SECURITY_AUDIT_MODE] = true; + } + } + + auto its_remote_access = its_security->get_child_optional("allow_remote_clients"); + if (its_remote_access) { + if (is_configured_[ET_SECURITY_REMOTE_ACCESS]) { + VSOMEIP_WARNING << "Multiple definitions for security audit mode (" + << "(check_credentials). Ignoring definition from " + << _element.name_; + } else { + is_remote_access_allowed_ = (its_remote_access->data() == "true"); + is_configured_[ET_SECURITY_REMOTE_ACCESS] = true; + } + } + } + + } catch (...) { + } + +#ifndef VSOMEIP_DISABLE_SECURITY + if (!is_security_external()) + policy_manager_->load(_element); +#endif // !VSOMEIP_DISABLE_SECURITY +} + + +void configuration_impl::load_selective_broadcasts_support(const configuration_element &_element) { + try { + auto its_service_discovery = _element.tree_.get_child("supports_selective_broadcasts"); + for (auto i = its_service_discovery.begin(); + i != its_service_discovery.end(); ++i) { + std::string its_value(i->second.data()); + supported_selective_addresses.insert(its_value); + } + } catch (...) { + } +} + + +void +configuration_impl::load_partitions(const configuration_element &_element) { + + try { + auto its_partitions = _element.tree_.get_child("partitions"); + for (auto i = its_partitions.begin(); i != its_partitions.end(); ++i) { + load_partition(i->second); + } + } catch (...) { + } +} + +void +configuration_impl::load_partition(const boost::property_tree::ptree &_tree) { + + static partition_id_t its_partition_id(VSOMEIP_DEFAULT_PARTITION_ID); + + try { + + std::stringstream its_converter; + std::map<service_t, std::set<instance_t> > its_partition_members; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + service_t its_service(0x0); + instance_t its_instance(0x0); + std::string its_service_s, its_instance_s; + + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::string its_key(j->first); + std::string its_data(j->second.data()); + + its_converter.str(""); + its_converter.clear(); + + if (its_data.find("0x") != std::string::npos) + its_converter << std::hex; + else + its_converter << std::dec; + its_converter << its_data; + + if (its_key == "service") { + its_converter >> its_service; + its_service_s = its_data; + } else if (its_key == "instance") { + its_converter >> its_instance; + its_instance_s = its_data; + } + } + + if (its_service > 0 && its_instance > 0) + its_partition_members[its_service].insert(its_instance); + else + VSOMEIP_ERROR << "P: <" << its_service_s << "." + << its_instance_s << "> is no valid service instance."; + + } + + if (!its_partition_members.empty()) { + std::lock_guard<std::mutex> its_lock(partitions_mutex_); + its_partition_id++; + + std::stringstream its_log; + its_log << "P" + << std::dec << static_cast<int>(its_partition_id) + << " ["; + + for (const auto &p : its_partition_members) { + for (const auto &m : p.second) { + partitions_[p.first][m] = its_partition_id; + its_log << "<" + << std::setfill('0') << std::hex + << std::setw(4) << p.first << "." + << std::setw(4) << m + << ">"; + } + } + + its_log << "]"; + VSOMEIP_INFO << its_log.str(); + } + } catch (...) { + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Internal helper +/////////////////////////////////////////////////////////////////////////////// +void configuration_impl::set_magic_cookies_unicast_address() { + // get services with static routing that have magic cookies enabled + std::map<std::string, std::set<uint16_t> > its_magic_cookies_ = magic_cookies_; + its_magic_cookies_.erase(default_unicast_); + + //set unicast address of host for all services without static routing + its_magic_cookies_[get_unicast_address().to_string()].insert( + magic_cookies_[default_unicast_].begin(), + magic_cookies_[default_unicast_].end()); + magic_cookies_.clear(); + magic_cookies_ = its_magic_cookies_; +} + +bool configuration_impl::is_internal_service(service_t _service, + instance_t _instance) const { + + for (auto its_range : internal_service_ranges_) { + if (_service >= its_range.first_service_ && + _service <= its_range.last_service_ && + _instance >= its_range.first_instance_ && + _instance <= its_range.last_instance_) { + return true; + } + } + return false; +} + +bool configuration_impl::is_in_port_range(uint16_t _port, + std::pair<uint16_t, uint16_t> _port_range) const { + + if (_port >= _port_range.first && + _port <= _port_range.second ) { + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Public interface +/////////////////////////////////////////////////////////////////////////////// +const std::string &configuration_impl::get_network() const { + return network_; +} + +const boost::asio::ip::address & configuration_impl::get_unicast_address() const { + return unicast_; +} + +const boost::asio::ip::address& configuration_impl::get_netmask() const { + return netmask_; +} + +unsigned short configuration_impl::get_prefix() const { + return prefix_; +} + +const std::string &configuration_impl::get_device() const { + return device_; +} + +diagnosis_t configuration_impl::get_diagnosis_address() const { + return diagnosis_; +} + +diagnosis_t configuration_impl::get_diagnosis_mask() const { + return diagnosis_mask_; +} + +bool configuration_impl::is_v4() const { + return unicast_.is_v4(); +} + +bool configuration_impl::is_v6() const { + return unicast_.is_v6(); +} + +bool configuration_impl::has_console_log() const { + return has_console_log_; +} + +bool configuration_impl::has_file_log() const { + return has_file_log_; +} + +bool configuration_impl::has_dlt_log() const { + return has_dlt_log_; +} + +const std::string & configuration_impl::get_logfile() const { + return logfile_; +} + +vsomeip_v3::logger::level_e configuration_impl::get_loglevel() const { + std::unique_lock<std::mutex> its_lock(mutex_loglevel_); + return loglevel_; +} + +std::string configuration_impl::get_unicast_address(service_t _service, + instance_t _instance) const { + std::string its_unicast_address(""); + auto its_service = find_service(_service, _instance); + if (its_service) { + its_unicast_address = its_service->unicast_address_; + } + + if (its_unicast_address == default_unicast_ || its_unicast_address == "") { + its_unicast_address = get_unicast_address().to_string(); + } + return its_unicast_address; +} + +uint16_t configuration_impl::get_reliable_port(service_t _service, + instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + uint16_t its_reliable(ILLEGAL_PORT); + auto its_service = find_service_unlocked(_service, _instance); + if (its_service) + its_reliable = its_service->reliable_; + + return its_reliable; +} + +uint16_t configuration_impl::get_unreliable_port(service_t _service, + instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + uint16_t its_unreliable = ILLEGAL_PORT; + auto its_service = find_service_unlocked(_service, _instance); + if (its_service) + its_unreliable = its_service->unreliable_; + + return its_unreliable; +} + +void configuration_impl::get_configured_timing_requests( + service_t _service, const std::string &_ip_target, + std::uint16_t _port_target, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const { + + if (_debounce_time == nullptr || _max_retention_time == nullptr) { + return; + } + + auto its_service = find_service(_service, _ip_target, _port_target); + if (its_service) { + auto find_method = its_service->debounce_times_requests_.find(_method); + if (find_method != its_service->debounce_times_requests_.end()) { + *_debounce_time = find_method->second[0]; + *_max_retention_time = find_method->second[1]; + return; + } + } + + *_debounce_time = npdu_default_debounce_requ_; + *_max_retention_time = npdu_default_max_retention_requ_; +} + +void configuration_impl::get_configured_timing_responses( + service_t _service, const std::string &_ip_service, + std::uint16_t _port_service, method_t _method, + std::chrono::nanoseconds *_debounce_time, + std::chrono::nanoseconds *_max_retention_time) const { + if (_debounce_time == nullptr || _max_retention_time == nullptr) { + return; + } + + auto its_service = find_service(_service, _ip_service, _port_service); + if (its_service) { + auto find_method = its_service->debounce_times_responses_.find(_method); + if (find_method != its_service->debounce_times_responses_.end()) { + *_debounce_time = find_method->second[0]; + *_max_retention_time = find_method->second[1]; + return; + } + } + + *_debounce_time = npdu_default_debounce_resp_; + *_max_retention_time = npdu_default_max_retention_resp_; +} + +bool configuration_impl::is_someip(service_t _service, + instance_t _instance) const { + auto its_service = find_service(_service, _instance); + if (its_service) + return (its_service->protocol_ == "someip"); + return true; // we need to explicitely configure a service to + // be something else than SOME/IP +} + +bool configuration_impl::get_client_port( + service_t _service, instance_t _instance, + uint16_t _remote_port, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports, + uint16_t &_client_port) const { + bool is_configured(false); + _client_port = ILLEGAL_PORT; + + uint16_t its_specific_port(ILLEGAL_PORT); + if (find_specific_port(its_specific_port, _service, _instance, _reliable, _used_client_ports)) { + is_configured = true; + if (its_specific_port != ILLEGAL_PORT) { + _client_port = its_specific_port; + return true; + } + } + + // No specific port configuration found, use generic configuration + uint16_t its_port(ILLEGAL_PORT); + if (find_port(its_port, _remote_port, _reliable, _used_client_ports)) { + is_configured = true; + if (its_port != ILLEGAL_PORT) { + _client_port = its_port; + return true; + } + } + + if (!is_configured) { + // Neither specific not generic configurarion available, + // use dynamic port configuration! + _client_port = 0; + return true; + } + + // Configured ports do exist, but they are all in use + VSOMEIP_ERROR << "Cannot find free client port for communication to service [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::dec << _remote_port << "." + << std::boolalpha <<_reliable << "]"; + + return false; +} + +bool configuration_impl::has_enabled_magic_cookies(const std::string &_address, + uint16_t _port) const { + bool has_enabled(false); + auto find_address = magic_cookies_.find(_address); + if (find_address != magic_cookies_.end()) { + auto find_port = find_address->second.find(_port); + if (find_port != find_address->second.end()) { + has_enabled = true; + } + } + return has_enabled; +} + +bool configuration_impl::is_routing_enabled() const { + return routing_.is_enabled_; +} + +const std::string & +configuration_impl::get_routing_host_name() const { + + return routing_.host_.name_; +} + +const boost::asio::ip::address & +configuration_impl::get_routing_host_address() const { + + return routing_.host_.unicast_; +} + +port_t +configuration_impl::get_routing_host_port() const { + + return routing_.host_.port_; +} + +const boost::asio::ip::address & +configuration_impl::get_routing_guest_address() const { + + return routing_.guests_.unicast_; +} + +std::set<std::pair<port_t, port_t> > +configuration_impl::get_routing_guest_ports(uid_t _uid, gid_t _gid) const { + + auto found = routing_.guests_.ports_.find({ _uid, _gid }); + if (found != routing_.guests_.ports_.end()) + return found->second; + + found = routing_.guests_.ports_.find({ _uid, ANY_GID }); + if (found != routing_.guests_.ports_.end()) + return found->second; + + found = routing_.guests_.ports_.find({ ANY_UID, _gid }); + if (found != routing_.guests_.ports_.end()) + return found->second; + + found = routing_.guests_.ports_.find({ ANY_UID, ANY_GID }); + if (found != routing_.guests_.ports_.end()) + return found->second; + + return std::set<std::pair<port_t, port_t> >(); +} + +bool +configuration_impl::is_local_routing() const { + + bool is_local(true); + try { + is_local = routing_.host_.unicast_.is_unspecified() || + routing_.host_.unicast_.is_multicast(); + } catch (...) { + } + + return is_local; +} + +client_t configuration_impl::get_id(const std::string &_name) const { + client_t its_client(VSOMEIP_CLIENT_UNSET); + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_client = found_application->second.client_; + } + + return its_client; +} + +bool configuration_impl::is_configured_client_id(client_t _id) const { + return (client_identifiers_.find(_id) != client_identifiers_.end()); +} + +std::size_t configuration_impl::get_request_debouncing(const std::string &_name) const { + size_t its_request_debouncing(VSOMEIP_REQUEST_DEBOUNCE_TIME); + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_request_debouncing = found_application->second.request_debouncing_; + } + + return its_request_debouncing; +} + +std::size_t configuration_impl::get_io_thread_count(const std::string &_name) const { + std::size_t its_io_thread_count = VSOMEIP_DEFAULT_IO_THREAD_COUNT; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_io_thread_count = found_application->second.thread_count_; + } + + return its_io_thread_count; +} + +int configuration_impl::get_io_thread_nice_level(const std::string &_name) const { + int its_io_thread_nice_level = VSOMEIP_DEFAULT_IO_THREAD_NICE_LEVEL; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_io_thread_nice_level = found_application->second.nice_level_; + } + + return its_io_thread_nice_level; +} + +std::size_t configuration_impl::get_max_dispatchers( + const std::string &_name) const { + + std::size_t its_max_dispatchers(VSOMEIP_MAX_DISPATCHERS); + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_max_dispatchers = found_application->second.max_dispatchers_; + } + + return its_max_dispatchers; +} + +std::size_t configuration_impl::get_max_dispatch_time( + const std::string &_name) const { + std::size_t its_max_dispatch_time = VSOMEIP_MAX_DISPATCH_TIME; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_max_dispatch_time = found_application->second.max_dispatch_time_; + } + + return its_max_dispatch_time; +} + +std::size_t configuration_impl::get_max_detached_thread_wait_time(const std::string& _name) const { + std::size_t its_max_detached_thread_wait_time = VSOMEIP_MAX_WAIT_TIME_DETACHED_THREADS; + + if (auto found_application = applications_.find(_name); + found_application != applications_.end()) { + its_max_detached_thread_wait_time = found_application->second.max_detach_thread_wait_time_; + } + + return its_max_detached_thread_wait_time; +} + +bool configuration_impl::has_session_handling(const std::string &_name) const { + + bool its_value(true); + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) + its_value = found_application->second.has_session_handling_; + + return its_value; +} + +std::set<std::pair<service_t, instance_t> > +configuration_impl::get_remote_services() const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + std::set<std::pair<service_t, instance_t> > its_remote_services; + for (const auto& i : services_) { + for (const auto& j : i.second) { + if (is_remote(j.second)) { + its_remote_services.insert(std::make_pair(i.first, j.first)); + } + } + } + return its_remote_services; +} + +bool configuration_impl::is_mandatory(const std::string &_name) const { + std::set<std::string> its_candidates; + for (const auto& m : mandatory_) { + if (m.size() <= _name.size()) { + its_candidates.insert(m); + } + } + + if (its_candidates.empty()) + return false; + + for (const auto& c : its_candidates) { + if (std::equal(c.rbegin(), c.rend(), _name.rbegin())) { + return true; + } + } + + return false; +} + +void configuration_impl::set_mandatory(const std::string &_input) { + if (_input.length() > 0) { + auto found_separator = _input.find(','); + std::string its_mandatory_file = _input.substr(0, found_separator); + trim(its_mandatory_file); + mandatory_.insert(its_mandatory_file); + while (found_separator != std::string::npos) { + auto last_separator = found_separator+1; + found_separator = _input.find(',', last_separator); + its_mandatory_file + = _input.substr(last_separator, found_separator - last_separator); + trim(its_mandatory_file); + mandatory_.insert(its_mandatory_file); + } + } +} + +void configuration_impl::trim(std::string &_s) { + _s.erase( + _s.begin(), + std::find_if( + _s.begin(), + _s.end(), + [](const auto ch) { return !std::isspace(ch); } + ) + ); + + _s.erase( + std::find_if( + _s.rbegin(), + _s.rend(), + [](const auto ch) { return !std::isspace(ch); } + ).base(), + _s.end() + ); +} + +bool configuration_impl::is_remote(const std::shared_ptr<service>& _service) const { + return (_service->unicast_address_ != default_unicast_ && + _service->unicast_address_ != "" && + _service->unicast_address_ != unicast_.to_string() && + _service->unicast_address_ != VSOMEIP_UNICAST_ADDRESS); +} + +bool configuration_impl::get_multicast(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + std::string &_address, uint16_t &_port) const +{ + std::shared_ptr<eventgroup> its_eventgroup + = find_eventgroup(_service, _instance, _eventgroup); + if (!its_eventgroup) + return false; + + if (its_eventgroup->multicast_address_.empty()) + return false; + + _address = its_eventgroup->multicast_address_; + _port = its_eventgroup->multicast_port_; + return true; +} + +uint8_t configuration_impl::get_threshold(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const { + std::shared_ptr<eventgroup> its_eventgroup + = find_eventgroup(_service, _instance, _eventgroup); + return (its_eventgroup ? its_eventgroup->threshold_ : 0); +} + +std::shared_ptr<client> configuration_impl::find_client(service_t _service, + instance_t _instance) const { + std::list<std::shared_ptr<client>>::const_iterator it; + + for (it = clients_.begin(); it != clients_.end(); ++it){ + // client was configured for specific service / instance + if ((*it)->service_ == _service + && (*it)->instance_ == _instance) { + return *it; + } + } + return nullptr; +} + +void configuration_impl::get_event_update_properties( + service_t _service, instance_t _instance, event_t _event, + std::chrono::milliseconds &_cycle, + bool &_change_resets_cycle, bool &_update_on_change) const { + + auto find_service = services_.find(_service); + if (find_service != services_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + auto its_service = find_instance->second; + auto find_event = its_service->events_.find(_event); + if (find_event != its_service->events_.end()) { + _cycle = find_event->second->cycle_; + _change_resets_cycle = find_event->second->change_resets_cycle_; + _update_on_change = find_event->second->update_on_change_; + return; + } + } + } + + _cycle = std::chrono::milliseconds::zero(); + _change_resets_cycle = false; + _update_on_change = true; +} + + +bool configuration_impl::find_port(uint16_t &_port, uint16_t _remote, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports) const { + bool is_configured(false); + std::list<std::shared_ptr<client>>::const_iterator it; + + for (it = clients_.begin(); it != clients_.end(); ++it) { + if (_remote != ILLEGAL_PORT && is_in_port_range(_remote, + (*it)->remote_ports_[_reliable])) { + is_configured = true; + uint16_t its_port(ILLEGAL_PORT); + if ((*it)->last_used_client_port_[_reliable] != ILLEGAL_PORT && + is_in_port_range(((*it)->last_used_client_port_[_reliable]), + (*it)->client_ports_[_reliable])) { + its_port = ++((*it)->last_used_client_port_[_reliable]); + ((*it)->last_used_client_port_[_reliable])++; + } else { + ((*it)->last_used_client_port_[_reliable])++; + // on initial start of port search + if ((*it)->last_used_client_port_[_reliable] == ILLEGAL_PORT) { + its_port = (*it)->client_ports_[_reliable].first; + } else { + continue; + } + } + while (its_port <= (*it)->client_ports_[_reliable].second) { + if (_used_client_ports[_reliable].find(its_port) + == _used_client_ports[_reliable].end()) { + _port = its_port; + (*it)->last_used_client_port_[_reliable] = its_port; + return true; + } + its_port++; + } + } + } + // no free port was found in _used_client_ports or last_used_port + // cannot be incremented for any client port range + // -> reset last used port for all available client port ranges + for (it = clients_.begin(); it != clients_.end(); ++it) { + if (_remote != ILLEGAL_PORT && is_in_port_range(_remote, + (*it)->remote_ports_[_reliable])) { + (*it)->last_used_client_port_[_reliable] = ILLEGAL_PORT; + } + } + // ensure that all configured client ports are checked from beginning + for (it = clients_.begin(); it != clients_.end(); ++it) { + if (_remote != ILLEGAL_PORT && is_in_port_range(_remote, + (*it)->remote_ports_[_reliable])) { + uint16_t its_port(ILLEGAL_PORT); + its_port = (*it)->client_ports_[_reliable].first; + while (its_port <= (*it)->client_ports_[_reliable].second) { + if (_used_client_ports[_reliable].find(its_port) + == _used_client_ports[_reliable].end()) { + _port = its_port; + (*it)->last_used_client_port_[_reliable] = its_port; + return true; + } + its_port++; + } + } + } + return is_configured; +} + +bool configuration_impl::find_specific_port(uint16_t &_port, service_t _service, + instance_t _instance, bool _reliable, + std::map<bool, std::set<uint16_t> > &_used_client_ports) const { + bool is_configured(false); + bool check_all(false); + std::list<std::shared_ptr<client>>::const_iterator it; + auto its_client = find_client(_service, _instance); + + // Check for service, instance specific port configuration + if (its_client && !its_client->ports_[_reliable].empty()) { + is_configured = true; + std::set<uint16_t>::const_iterator it; + if (its_client->last_used_specific_client_port_[_reliable] == ILLEGAL_PORT) { + it = its_client->ports_[_reliable].begin(); + } else { + it = its_client->ports_[_reliable].find( + its_client->last_used_specific_client_port_[_reliable]); + auto it_next = std::next(it, 1); + if (it_next != its_client->ports_[_reliable].end()) { + check_all = true; + it = it_next; + } else { + it = its_client->ports_[_reliable].begin(); + } + } + while (it != its_client->ports_[_reliable].end()) { + if (_used_client_ports[_reliable].find(*it) + == _used_client_ports[_reliable].end()) { + _port = *it; + its_client->last_used_specific_client_port_[_reliable] = *it; + VSOMEIP_INFO << "configuration_impl:find_specific_port #1:" + << " service: " << std::hex << _service + << " instance: " << _instance + << " reliable: " << std::dec << _reliable + << " return specific port: " << (uint32_t)_port; + return true; + } + ++it; + } + if (check_all) { + // no free port was found + // ensure that all configured client ports are checked from beginning + for (auto its_port : _used_client_ports[_reliable]) { + if (_used_client_ports[_reliable].find(its_port) + == _used_client_ports[_reliable].end()) { + _port = its_port; + its_client->last_used_specific_client_port_[_reliable] = its_port; + VSOMEIP_INFO << "configuration_impl:find_specific_port #2:" + << " service: " << std::hex << _service + << " instance: " << _instance + << " reliable: " << std::dec << _reliable + << " return specific port: " << (uint32_t)_port; + return true; + } + } + } + its_client->last_used_specific_client_port_[_reliable] = ILLEGAL_PORT; + } + return is_configured; +} + +reliability_type_e +configuration_impl::get_event_reliability(service_t _service, + instance_t _instance, event_t _event) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + reliability_type_e its_reliability(reliability_type_e::RT_UNKNOWN); + auto its_service = find_service_unlocked(_service, _instance); + if (its_service) { + auto its_event = its_service->events_.find(_event); + if (its_event != its_service->events_.end()) { + its_reliability = its_event->second->reliability_; + } + } + return its_reliability; +} + +reliability_type_e +configuration_impl::get_service_reliability(service_t _service, + instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + reliability_type_e its_reliability(reliability_type_e::RT_UNKNOWN); + auto its_service = find_service_unlocked(_service, _instance); + if (its_service) { + if (its_service->reliable_ != ILLEGAL_PORT) { + if (its_service->unreliable_ != ILLEGAL_PORT) { + its_reliability = reliability_type_e::RT_BOTH; + } else { + its_reliability = reliability_type_e::RT_RELIABLE; + } + } else { + its_reliability = reliability_type_e::RT_UNRELIABLE; + } + } + return its_reliability; +} + +std::shared_ptr<service> configuration_impl::find_service(service_t _service, + instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + return find_service_unlocked(_service, _instance); +} + +std::shared_ptr<service> configuration_impl::find_service_unlocked(service_t _service, + instance_t _instance) const { + std::shared_ptr<service> its_service; + auto find_service = services_.find(_service); + if (find_service != services_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + its_service = find_instance->second; + } + } + return its_service; +} + +std::shared_ptr<service> +configuration_impl::find_service(service_t _service, + const std::string &_address, std::uint16_t _port) const { + + std::shared_ptr<service> its_service; + + auto find_address = services_by_ip_port_.find(_address); + if (find_address != services_by_ip_port_.end()) { + auto find_port = find_address->second.find(_port); + if(find_port != find_address->second.end()) { + auto find_service = find_port->second.find(_service); + if(find_service != find_port->second.end()) { + its_service = find_service->second; + } + } + } + + return its_service; +} + +std::shared_ptr<eventgroup> configuration_impl::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::shared_ptr<eventgroup> its_eventgroup; + auto its_service = find_service(_service, _instance); + if (its_service) { + auto find_eventgroup = its_service->eventgroups_.find(_eventgroup); + if (find_eventgroup != its_service->eventgroups_.end()) { + its_eventgroup = find_eventgroup->second; + } + } + return its_eventgroup; +} + +std::uint32_t configuration_impl::get_max_message_size_local() const { + if (max_local_message_size_ == 0 + && (VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0 + || VSOMEIP_MAX_TCP_MESSAGE_SIZE == 0)) { + // no limit specified in configuration file and + // defines are set to unlimited + return MESSAGE_SIZE_UNLIMITED; + } + + uint32_t its_max_message_size = max_local_message_size_; + if (VSOMEIP_MAX_TCP_MESSAGE_SIZE >= its_max_message_size) { + its_max_message_size = VSOMEIP_MAX_TCP_MESSAGE_SIZE; + } + if (VSOMEIP_MAX_UDP_MESSAGE_SIZE > its_max_message_size) { + its_max_message_size = VSOMEIP_MAX_UDP_MESSAGE_SIZE; + } + if (its_max_message_size < max_configured_message_size_) { + its_max_message_size = max_configured_message_size_; + } + + // add sizes of the the routing_manager_proxy's messages + // to the routing_manager stub + return std::uint32_t(its_max_message_size + protocol::SEND_COMMAND_HEADER_SIZE); +} + +std::uint32_t configuration_impl::get_max_message_size_reliable( + const std::string& _address, std::uint16_t _port) const { + const auto its_address = message_sizes_.find(_address); + if(its_address != message_sizes_.end()) { + const auto its_port = its_address->second.find(_port); + if(its_port != its_address->second.end()) { + return its_port->second; + } + } + return (max_reliable_message_size_ == 0) ? + ((VSOMEIP_MAX_TCP_MESSAGE_SIZE == 0) ? MESSAGE_SIZE_UNLIMITED : + VSOMEIP_MAX_TCP_MESSAGE_SIZE) : max_reliable_message_size_; +} + +std::uint32_t configuration_impl::get_max_message_size_unreliable() const { + return (max_unreliable_message_size_ == 0) ? + MESSAGE_SIZE_UNLIMITED : max_unreliable_message_size_; +} + +std::uint32_t configuration_impl::get_buffer_shrink_threshold() const { + return buffer_shrink_threshold_; +} + +bool configuration_impl::supports_selective_broadcasts(const boost::asio::ip::address &_address) const { + return supported_selective_addresses.find(_address.to_string()) != supported_selective_addresses.end(); +} + +bool configuration_impl::log_version() const { + return log_version_; +} + +uint32_t configuration_impl::get_log_version_interval() const { + return log_version_interval_; +} + +bool configuration_impl::is_offered_remote(service_t _service, instance_t _instance) const { + uint16_t reliable_port = get_reliable_port(_service, _instance); + uint16_t unreliable_port = get_unreliable_port(_service, _instance); + return (reliable_port != ILLEGAL_PORT || unreliable_port != ILLEGAL_PORT); +} + +bool configuration_impl::is_local_service(service_t _service, instance_t _instance) const { + std::shared_ptr<service> s = find_service(_service, _instance); + if (s && !is_remote(s)) { + return true; + } + if (is_internal_service(_service, _instance)) { + return true; + } + + return false; +} + +// Service Discovery configuration +bool configuration_impl::is_sd_enabled() const { + return is_sd_enabled_; +} + +const std::string & configuration_impl::get_sd_multicast() const { + return sd_multicast_; +} + +uint16_t configuration_impl::get_sd_port() const { + return sd_port_; +} + +const std::string & configuration_impl::get_sd_protocol() const { + return sd_protocol_; +} + +uint32_t configuration_impl::get_sd_initial_delay_min() const { + return sd_initial_delay_min_; +} + +uint32_t configuration_impl::get_sd_initial_delay_max() const { + return sd_initial_delay_max_; +} + +int32_t configuration_impl::get_sd_repetitions_base_delay() const { + return sd_repetitions_base_delay_; +} + +uint8_t configuration_impl::get_sd_repetitions_max() const { + return sd_repetitions_max_; +} + +ttl_t configuration_impl::get_sd_ttl() const { + return sd_ttl_; +} + +int32_t configuration_impl::get_sd_cyclic_offer_delay() const { + return sd_cyclic_offer_delay_; +} + +int32_t configuration_impl::get_sd_request_response_delay() const { + return sd_request_response_delay_; +} + +std::uint32_t configuration_impl::get_sd_offer_debounce_time() const { + return sd_offer_debounce_time_; +} + +std::uint32_t configuration_impl::get_sd_find_debounce_time() const { + return sd_find_debounce_time_; +} + +// Trace configuration +std::shared_ptr<cfg::trace> configuration_impl::get_trace() const { + return trace_; +} + +// Watchdog config +bool configuration_impl::is_watchdog_enabled() const { + return watchdog_->is_enabeled_; +} + +uint32_t configuration_impl::get_watchdog_timeout() const { + return watchdog_->timeout_in_ms_; +} + +uint32_t configuration_impl::get_allowed_missing_pongs() const { + return watchdog_->missing_pongs_allowed_; +} +std::uint32_t configuration_impl::get_permissions_uds() const { + return permissions_uds_; +} + +std::map<plugin_type_e, std::set<std::string>> configuration_impl::get_plugins( + const std::string &_name) const { + + std::map<plugin_type_e, std::set<std::string>> its_plugins; + + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_plugins = found_application->second.plugins_; + } + + return its_plugins; +} + +void configuration_impl::set_configuration_path(const std::string &_path) { + configuration_path_ = _path; +} + +std::map<std::string, std::string> configuration_impl::get_additional_data( + const std::string &_application_name, + const std::string &_plugin_name) { + + return plugins_additional_[_application_name][_plugin_name]; +} + +bool configuration_impl::is_e2e_enabled() const { + return e2e_enabled_; +} + +void configuration_impl::load_e2e(const configuration_element &_element) { +#ifdef _WIN32 + return; +#endif + try { + auto optional = _element.tree_.get_child_optional("e2e"); + if (!optional) { + return; + } + auto found_e2e = _element.tree_.get_child("e2e"); + for (auto its_e2e = found_e2e.begin(); + its_e2e != found_e2e.end(); ++its_e2e) { + if (its_e2e->first == "e2e_enabled") { + if (its_e2e->second.data() == "true") { + e2e_enabled_ = true; + } + } + if (its_e2e->first == "protected") { + for (auto its_protected = its_e2e->second.begin(); + its_protected != its_e2e->second.end(); ++its_protected) { + load_e2e_protected(its_protected->second); + } + } + } + } catch (...) { + } +} + +void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_tree) { + + std::string variant(""); + std::string profile(""); + service_t service_id(0); + event_t event_id(0); + + e2e::custom_parameters_t custom_parameters; + + for (auto l = _tree.begin(); l != _tree.end(); ++l) { + std::stringstream its_converter; + if (l->first == "service_id") { + std::string value = l->second.data(); + if (value.size() > 1 && value[0] == '0' && value[1] == 'x') { + its_converter << std::hex << value; + } else { + its_converter << std::dec << value; + } + its_converter >> service_id; + } else if (l->first == "event_id") { + std::string value = l->second.data(); + if (value.size() > 1 && value[0] == '0' && value[1] == 'x') { + its_converter << std::hex << value; + } else { + its_converter << std::dec << value; + } + its_converter >> event_id; + } else if (l->first == "variant") { + std::string value = l->second.data(); + its_converter << value; + its_converter >> variant; + } else if (l->first == "profile") { + std::string value = l->second.data(); + its_converter << value; + its_converter >> profile; + } else { + custom_parameters[l->first.data()] = l->second.data(); + } + } + e2e_configuration_[std::make_pair(service_id, event_id)] = std::make_shared<cfg::e2e>( + variant, + profile, + service_id, + event_id, + std::move(custom_parameters) + ); +} + +std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> configuration_impl::get_e2e_configuration() const { + return e2e_configuration_; +} + +bool configuration_impl::log_memory() const { + return log_memory_; +} + +uint32_t configuration_impl::get_log_memory_interval() const { + return log_memory_interval_; +} + +bool configuration_impl::log_status() const { + return log_status_; +} + +uint32_t configuration_impl::get_log_status_interval() const { + return log_status_interval_; +} + +void configuration_impl::load_ttl_factors( + const boost::property_tree::ptree &_tree, ttl_map_t* _target) { + const service_t ILLEGAL_VALUE(0xffff); + for (const auto& i : _tree) { + service_t its_service(ILLEGAL_VALUE); + instance_t its_instance(ILLEGAL_VALUE); + configuration::ttl_factor_t its_ttl_factor(0); + + for (const auto& j : i.second) { + std::string its_key(j.first); + std::string its_value(j.second.data()); + std::stringstream its_converter; + + if (its_key == "ttl_factor") { + its_converter << its_value; + its_converter >> its_ttl_factor; + } else { + // Trim "its_value" + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "service") { + its_converter >> its_service; + } else if (its_key == "instance") { + its_converter >> its_instance; + } + } + } + if (its_service != ILLEGAL_VALUE + && its_instance != ILLEGAL_VALUE + && its_ttl_factor > 0) { + (*_target)[its_service][its_instance] = its_ttl_factor; + } else { + VSOMEIP_ERROR << "Invalid ttl factor configuration"; + } + } +} + +configuration::ttl_map_t configuration_impl::get_ttl_factor_offers() const { + return ttl_factors_offers_; +} + +configuration::ttl_map_t configuration_impl::get_ttl_factor_subscribes() const { + return ttl_factors_subscriptions_; +} + +configuration::endpoint_queue_limit_t +configuration_impl::get_endpoint_queue_limit( + const std::string& _address, std::uint16_t _port) const { + auto found_address = endpoint_queue_limits_.find(_address); + if (found_address != endpoint_queue_limits_.end()) { + auto found_port = found_address->second.find(_port); + if (found_port != found_address->second.end()) { + return found_port->second; + } + } + return endpoint_queue_limit_external_; +} + +configuration::endpoint_queue_limit_t +configuration_impl::get_endpoint_queue_limit_local() const { + return endpoint_queue_limit_local_; +} + +void +configuration_impl::load_endpoint_queue_sizes(const configuration_element &_element) { + const std::string endpoint_queue_limits("endpoint-queue-limits"); + const std::string endpoint_queue_limit_external("endpoint-queue-limit-external"); + const std::string endpoint_queue_limit_local("endpoint-queue-limit-local"); + + try { + if (_element.tree_.get_child_optional(endpoint_queue_limit_external)) { + if (is_configured_[ET_ENDPOINT_QUEUE_LIMIT_EXTERNAL]) { + VSOMEIP_WARNING << "Multiple definitions for " + << endpoint_queue_limit_external + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_ENDPOINT_QUEUE_LIMIT_EXTERNAL] = true; + auto mpsl = _element.tree_.get_child( + endpoint_queue_limit_external); + std::string s(mpsl.data()); + try { + endpoint_queue_limit_external_ = + static_cast<configuration::endpoint_queue_limit_t>(std::stoul( + s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<<__func__ << ": " << endpoint_queue_limit_external + << " " << e.what(); + } + } + } + if (_element.tree_.get_child_optional(endpoint_queue_limit_local)) { + if (is_configured_[ET_ENDPOINT_QUEUE_LIMIT_LOCAL]) { + VSOMEIP_WARNING << "Multiple definitions for " + << endpoint_queue_limit_local + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_ENDPOINT_QUEUE_LIMIT_LOCAL] = true; + auto mpsl = _element.tree_.get_child(endpoint_queue_limit_local); + std::string s(mpsl.data()); + try { + endpoint_queue_limit_local_= + static_cast<configuration::endpoint_queue_limit_t>( + std::stoul(s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": "<< endpoint_queue_limit_local + << " " << e.what(); + } + } + } + + if (_element.tree_.get_child_optional(endpoint_queue_limits)) { + if (is_configured_[ET_ENDPOINT_QUEUE_LIMITS]) { + VSOMEIP_WARNING << "Multiple definitions for " + << endpoint_queue_limits + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_ENDPOINT_QUEUE_LIMITS] = true; + const std::string unicast("unicast"); + const std::string ports("ports"); + const std::string port("port"); + const std::string queue_size_limit("queue-size-limit"); + + for (const auto& i : _element.tree_.get_child(endpoint_queue_limits)) { + if (!i.second.get_child_optional(unicast) + || !i.second.get_child_optional(ports)) { + continue; + } + std::string its_unicast(i.second.get_child(unicast).data()); + for (const auto& j : i.second.get_child(ports)) { + + if (!j.second.get_child_optional(port) + || !j.second.get_child_optional(queue_size_limit)) { + continue; + } + + std::uint16_t its_port = ILLEGAL_PORT; + std::uint32_t its_queue_size_limit = 0; + + try { + std::string p(j.second.get_child(port).data()); + its_port = static_cast<std::uint16_t>(std::stoul(p.c_str(), + NULL, 10)); + std::string s(j.second.get_child(queue_size_limit).data()); + its_queue_size_limit = static_cast<std::uint32_t>(std::stoul( + s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << ":" << e.what(); + } + + if (its_port == ILLEGAL_PORT || its_queue_size_limit == 0) { + continue; + } + + endpoint_queue_limits_[its_unicast][its_port] = its_queue_size_limit; + } + } + } + } + } catch (...) { + } +} + +void +configuration_impl::load_debounce(const configuration_element &_element) { + try { + auto its_debounce = _element.tree_.get_child("debounce"); + for (auto i = its_debounce.begin(); i != its_debounce.end(); ++i) { + load_service_debounce(i->second, debounces_); + } + } catch (...) { + } +} + +void +configuration_impl::load_service_debounce( + const boost::property_tree::ptree &_tree, + debounce_configuration_t &_debounces) { + + service_t its_service(0); + instance_t its_instance(0); + std::map<event_t, std::shared_ptr<debounce_filter_impl_t>> its_debounces; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "service") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_service; + } else if (its_key == "instance") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_instance; + } else if (its_key == "events") { + load_events_debounce(i->second, its_debounces); + } + } + + // TODO: Improve error handling! + if (its_service > 0 && its_instance > 0 && !its_debounces.empty()) { + auto find_service = debounces_.find(its_service); + if (find_service != debounces_.end()) { + auto find_instance = find_service->second.find(its_instance); + if (find_instance != find_service->second.end()) { + VSOMEIP_ERROR << "Multiple debounce configurations for service " + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance; + return; + } + } + _debounces[its_service][its_instance] = its_debounces; + } +} + +void +configuration_impl::load_events_debounce( + const boost::property_tree::ptree &_tree, + std::map<event_t, std::shared_ptr<debounce_filter_impl_t> > &_debounces) { + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + load_event_debounce(i->second, _debounces); + } +} + +void +configuration_impl::load_event_debounce( + const boost::property_tree::ptree &_tree, + std::map<event_t, std::shared_ptr<debounce_filter_impl_t> > &_debounces) { + + event_t its_event(0); + auto its_debounce = std::make_shared<debounce_filter_impl_t>(); + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + if (its_key == "event") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_event; + } else if (its_key == "on_change") { + its_debounce->on_change_ = (its_value == "true"); + } else if (its_key == "on_change_resets_interval") { + its_debounce->on_change_resets_interval_ = (its_value == "true"); + } else if (its_key == "ignore") { + load_event_debounce_ignore(i->second, its_debounce->ignore_); + } else if (its_key == "interval") { + if (its_value == "never") { + its_debounce->interval_ = -1; + } else { + its_converter << std::dec << its_value; + its_converter >> its_debounce->interval_; + } + } else if (its_key == "send_current_value_after") { + its_debounce->send_current_value_after_ = (its_value == "true"); + } + } + + // TODO: Improve error handling + if (its_event > 0) { + auto find_event = _debounces.find(its_event); + if (find_event == _debounces.end()) { + _debounces[its_event] = its_debounce; + } + } +} + +void configuration_impl::load_event_debounce_ignore( + const boost::property_tree::ptree &_tree, + std::map<std::size_t, byte_t> &_ignore) { + std::size_t its_ignored; + byte_t its_mask; + std::stringstream its_converter; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_value = i->second.data(); + + its_mask = 0xff; + + if (!its_value.empty() + && std::find_if(its_value.begin(), its_value.end(), + [](char _c) { return !std::isdigit(_c); }) + == its_value.end()) { + its_converter.str(""); + its_converter.clear(); + its_converter << std::dec << its_value; + its_converter >> its_ignored; + + } else { + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::string its_ignore_key(j->first); + std::string its_ignore_value(j->second.data()); + + if (its_ignore_key == "index") { + its_converter.str(""); + its_converter.clear(); + its_converter << std::dec << its_ignore_value; + its_converter >> its_ignored; + } else if (its_ignore_key == "mask") { + its_converter.str(""); + its_converter.clear(); + + int its_tmp_mask; + its_converter << std::hex << its_ignore_value; + its_converter >> its_tmp_mask; + + its_mask = static_cast<byte_t>(its_tmp_mask); + } + } + } + + _ignore[its_ignored] = its_mask; + } +} + +void +configuration_impl::load_acceptances( + const configuration_element &_element) { + + std::string its_acceptances_key("acceptances"); + try { + auto its_acceptances = _element.tree_.get_child_optional(its_acceptances_key); + if (its_acceptances) { + if (is_configured_[ET_SD_ACCEPTANCE_REQUIRED]) { + VSOMEIP_WARNING << "Multiple definitions of " << its_acceptances_key + << " Ignoring definition from " << _element.name_; + return; + } + + for (auto i = its_acceptances->begin(); i != its_acceptances->end(); ++i) { + load_acceptance_data(i->second); + } + + is_configured_[ET_SD_ACCEPTANCE_REQUIRED] = true; + } + } catch (...) { + // Intentionally left empty + } +} + +void +configuration_impl::load_acceptance_data( + const boost::property_tree::ptree &_tree) { + + std::stringstream its_converter; + try { + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + + boost::asio::ip::address its_address; + std::string its_path; + std::map<bool, + std::pair<boost::icl::interval_set<std::uint16_t>, + boost::icl::interval_set<std::uint16_t> + > + > its_ports; + bool has_optional, has_secure, is_reliable; + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + + std::string its_key(i->first); + std::string its_value(i->second.data()); + + if (its_key == "address") { + its_address = boost::asio::ip::address::from_string(its_value); + } else if (its_key == "path") { + its_path = its_value; + } else if (its_key == "reliable" || its_key == "unreliable") { + + is_reliable = (its_key == "reliable"); + has_optional = has_secure = false; + + for (const auto &p : i->second) { + if (p.second.size()) { // range + std::uint16_t its_first(0); + std::uint16_t its_last(0); + port_type_e its_type(port_type_e::PT_OPTIONAL); + + for (const auto& range : p.second) { + const std::string its_key(range.first); + const std::string its_value(range.second.data()); + if (its_key == "first" || its_key == "last" || its_key == "port") { + its_converter << std::dec << its_value; + std::uint16_t its_port_value(0); + its_converter >> its_port_value; + its_converter.str(""); + its_converter.clear(); + if (its_key == "first") { + its_first = its_port_value; + } else if (its_key == "last") { + its_last = its_port_value; + } else if (its_key == "port") { + its_first = its_last = its_port_value; + } + } else if (its_key == "type") { + if (its_value == "secure") { + its_type = port_type_e::PT_SECURE; + } else if (its_value == "optional") { + its_type = port_type_e::PT_OPTIONAL; + } else { + its_type = port_type_e::PT_UNKNOWN; + } + } + } + if (its_type != port_type_e::PT_UNKNOWN) { + if (its_type == port_type_e::PT_OPTIONAL) { + has_optional = true; + if (its_first != 0 && its_last != 0) { + its_ports.operator [](is_reliable).first.insert( + boost::icl::interval<std::uint16_t>::closed(its_first, its_last)); + } + } else { + has_secure = true; + if (its_first != 0 && its_last != 0) { + its_ports.operator [](is_reliable).second.insert( + boost::icl::interval<std::uint16_t>::closed(its_first, its_last)); + } + } + } + } + } + + // If optional was not set, use default! + if (!has_optional) { + const auto its_optional_client = boost::icl::interval<std::uint16_t>::closed(30491, 30499); + const auto its_optional_client_spare = boost::icl::interval<std::uint16_t>::closed(30898, 30998); + const auto its_optional_server = boost::icl::interval<std::uint16_t>::closed(30501, 30599); + + its_ports.operator [](is_reliable).first.insert(its_optional_client); + its_ports.operator [](is_reliable).first.insert(its_optional_client_spare); + its_ports.operator [](is_reliable).first.insert(its_optional_server); + } + + // If secure was not set, use default! + if (!has_secure) { + const auto its_secure_client = boost::icl::interval<std::uint16_t>::closed(32491, 32499); + const auto its_secure_client_spare = boost::icl::interval<std::uint16_t>::closed(32898, 32998); + const auto its_secure_server = boost::icl::interval<std::uint16_t>::closed(32501, 32599); + + its_ports.operator [](is_reliable).second.insert(its_secure_client); + its_ports.operator [](is_reliable).second.insert(its_secure_client_spare); + its_ports.operator [](is_reliable).second.insert(its_secure_server); + } + } + } + + if (!its_address.is_unspecified()) { + sd_acceptance_rules_[its_address] = std::make_pair(its_path, its_ports); + } + } catch (...) { + // intentionally left empty + } +} + +bool configuration_impl::load_npdu_debounce_times_configuration( + const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree) { + bool is_loaded(true); + try { + for (const auto& i : _tree) { + const std::string its_key(i.first); + if (its_key == "requests") { + if (!load_npdu_debounce_times_for_service(_service, true, i.second)) { + is_loaded = false; + } + } else if (its_key == "responses") { + if (!load_npdu_debounce_times_for_service(_service, false, i.second)) { + is_loaded = false; + } + } + } + } catch (...) { + is_loaded = false; + } + return is_loaded; +} + +bool configuration_impl::load_npdu_debounce_times_for_service( + const std::shared_ptr<service>& _service, bool _is_request, + const boost::property_tree::ptree &_tree) { + const std::string dtime("debounce-time"); + const std::string rtime("maximum-retention-time"); + + bool is_loaded(true); + try { + std::stringstream its_converter; + for (const auto& i : _tree) { + const std::string its_method_str(i.first.data()); + if (its_method_str.size()) { + method_t its_method = 0xFFFF; + if (its_method_str.size() > 1 && its_method_str[0] == '0' + && its_method_str[1] == 'x') { + its_converter << std::hex << its_method_str; + } else { + its_converter << std::dec << its_method_str; + } + its_converter >> its_method; + its_converter.str(""); + its_converter.clear(); + + std::chrono::nanoseconds its_debounce_time( + npdu_default_debounce_requ_); + std::chrono::nanoseconds its_retention_time( + npdu_default_max_retention_requ_); + for (const auto& j : i.second) { + const std::string& key = j.first; + const std::uint64_t value = std::strtoull( + j.second.data().c_str(), + NULL, 10) * 1000000; + if (key == dtime) { + its_debounce_time = std::chrono::nanoseconds(value); + } else if (key == rtime) { + its_retention_time = std::chrono::nanoseconds(value); + } + } + if (_is_request) { + _service->debounce_times_requests_[its_method] + = {its_debounce_time, its_retention_time}; + } else { + _service->debounce_times_responses_[its_method] + = { its_debounce_time, its_retention_time}; + } + } + } + } catch (...) { + is_loaded = false; + } + return is_loaded; +} + +void configuration_impl::load_someip_tp( + const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree) { + try { + for (const auto& i : _tree) { + const std::string its_key(i.first); + if (its_key == "client-to-service") { + load_someip_tp_for_service(_service, i.second, true); + } else if (its_key == "service-to-client") { + load_someip_tp_for_service(_service, i.second, false); + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_someip_tp_for_service( + const std::shared_ptr<service>& _service, + const boost::property_tree::ptree &_tree, bool _is_request) { + try { + std::stringstream its_converter; + for (const auto& method : _tree) { + method_t its_method(0); + uint16_t its_max_segment_length(VSOMEIP_TP_MAX_SEGMENT_LENGTH_DEFAULT); + uint32_t its_separation_time(0); + + const std::string its_value(method.second.data()); + if (its_value.empty()) { + for (const auto &its_data : method.second) { + const std::string its_value(its_data.second.data()); + if (!its_value.empty()) { + if (its_data.first == "method") { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_method; + } else if (its_data.first == "max-segment-length") { + its_converter << std::dec << its_value; + its_converter >> its_max_segment_length; + + // Segment length must be multiple of 16 + // Ensure this by subtracting the rest + auto its_rest = std::uint16_t(its_max_segment_length % 16); + if (its_rest != 0) { + VSOMEIP_WARNING << "SOMEIP/TP: max-segment-length must be multiple of 16. Corrected " + << std::dec << its_max_segment_length << " to " + << std::dec << its_max_segment_length-its_rest; + + its_max_segment_length = std::uint16_t(its_max_segment_length - its_rest); + } + } else if (its_data.first == "separation-time") { + its_converter << std::dec << its_value; + its_converter >> its_separation_time; + its_separation_time *= std::uint32_t(1000); + } + } + its_converter.str(""); + its_converter.clear(); + } + } else { + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + its_converter >> its_method; + its_converter.str(""); + its_converter.clear(); + } + + if (its_method != 0) { + if (_is_request) { + const auto its_entry = _service->tp_client_config_.find(its_method); + if (its_entry == _service->tp_client_config_.end()) { + _service->tp_client_config_[its_method] + = std::make_pair(its_max_segment_length, its_separation_time); + } else { + VSOMEIP_WARNING << "SOME/IP-TP: Multiple client configurations for method [" + << std::hex << std::setfill('0') + << std::setw(4) << _service->service_ << "." + << std::setw(4) << _service->instance_ << "." + << std::setw(4) << its_method << "]:" + << " using (" << std::dec + << its_entry->second.first << ", " + << its_entry->second.second << ")"; + } + } else { + const auto its_entry = _service->tp_service_config_.find(its_method); + if (its_entry == _service->tp_service_config_.end()) { + _service->tp_service_config_[its_method] + = std::make_pair(its_max_segment_length, its_separation_time); + } else { + VSOMEIP_WARNING << "SOME/IP-TP: Multiple service configurations for method [" + << std::hex << std::setfill('0') + << std::setw(4) << _service->service_ << "." + << std::setw(4) << _service->instance_ << "." + << std::setw(4) << its_method << "]:" + << " using (" << std::dec + << its_entry->second.first << ", " + << std::dec << its_entry->second.second << ")"; + } + } + } else { + VSOMEIP_ERROR << "SOME/IP-TP configuration contains invalid entry. No valid method specified!"; + } + } + } catch (...) { + // intentionally left empty + } +} + +void +configuration_impl::load_udp_receive_buffer_size(const configuration_element &_element) { + const std::string its_buffer_size("udp-receive-buffer-size"); + try { + if (_element.tree_.get_child_optional(its_buffer_size)) { + if (is_configured_[ET_UDP_RECEIVE_BUFFER_SIZE]) { + VSOMEIP_WARNING << "Multiple definitions of " << its_buffer_size + << " Ignoring definition from " << _element.name_; + } else { + const std::string its_data(_element.tree_.get_child(its_buffer_size).data()); + try { + udp_receive_buffer_size_ = std::stoi(its_data.c_str(), nullptr, 10); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": " << its_buffer_size << " " << e.what(); + } + is_configured_[ET_UDP_RECEIVE_BUFFER_SIZE] = true; + } + } + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_secure_services(const configuration_element &_element) { + std::lock_guard<std::mutex> its_lock(secure_services_mutex_); + try { + auto its_services = _element.tree_.get_child("secure-services"); + for (auto i = its_services.begin(); i != its_services.end(); ++i) + load_secure_service(i->second); + } catch (...) { + // intentionally left empty + } +} + +void configuration_impl::load_secure_service(const boost::property_tree::ptree &_tree) { + try { + service_t its_service(0); + instance_t its_instance(0); + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + std::stringstream its_converter; + + // Trim "its_value" + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + if (its_key == "service") { + its_converter >> its_service; + } else if (its_key == "instance") { + its_converter >> its_instance; + } + } + + if (its_service != 0 && its_instance != 0) { + auto find_service = secure_services_.find(its_service); + if (find_service != secure_services_.end()) { + find_service->second.insert(its_instance); + } else { + secure_services_[its_service].insert(its_instance); + } + } + + } catch (...) { + // Intentionally left empty + } +} + +std::shared_ptr<debounce_filter_impl_t> +configuration_impl::get_debounce(const std::string &_name, + service_t _service, instance_t _instance, event_t _event) const { + + // Try to find application (client) specific debounce configuration + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + auto found_service = found_application->second.debounces_.find(_service); + if (found_service != found_application->second.debounces_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + return found_event->second; + } + } + } + } + + // If no application specific configuration was found, search for a + // generic + auto found_service = debounces_.find(_service); + if (found_service != debounces_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + return found_event->second; + } + } + } + return nullptr; +} + +void +configuration_impl::load_tcp_restart_settings(const configuration_element &_element) { + const std::string tcp_restart_aborts_max("tcp-restart-aborts-max"); + const std::string tcp_connect_time_max("tcp-connect-time-max"); + + try { + if (_element.tree_.get_child_optional(tcp_restart_aborts_max)) { + if (is_configured_[ET_TCP_RESTART_ABORTS_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for " + << tcp_restart_aborts_max + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_TCP_RESTART_ABORTS_MAX] = true; + auto mpsl = _element.tree_.get_child( + tcp_restart_aborts_max); + std::string s(mpsl.data()); + try { + tcp_restart_aborts_max_ = + static_cast<std::uint32_t>(std::stoul( + s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<<__func__ << ": " << tcp_restart_aborts_max + << " " << e.what(); + } + } + } + if (_element.tree_.get_child_optional(tcp_connect_time_max)) { + if (is_configured_[ET_TCP_CONNECT_TIME_MAX]) { + VSOMEIP_WARNING << "Multiple definitions for " + << tcp_connect_time_max + << " Ignoring definition from " << _element.name_; + } else { + is_configured_[ET_TCP_CONNECT_TIME_MAX] = true; + auto mpsl = _element.tree_.get_child(tcp_connect_time_max); + std::string s(mpsl.data()); + try { + tcp_connect_time_max_= + static_cast<std::uint32_t>( + std::stoul(s.c_str(), NULL, 10)); + } catch (const std::exception &e) { + VSOMEIP_ERROR<< __func__ << ": "<< tcp_connect_time_max + << " " << e.what(); + } + } + } + } catch (...) { + } +} + +std::uint32_t configuration_impl::get_max_tcp_restart_aborts() const { + return tcp_restart_aborts_max_; +} + +std::uint32_t configuration_impl::get_max_tcp_connect_time() const { + return tcp_connect_time_max_; +} + +bool configuration_impl::is_protected_device( + const boost::asio::ip::address& _address) const { + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + return (sd_acceptance_rules_active_.find(_address) + != sd_acceptance_rules_active_.end()); +} + +bool configuration_impl::is_protected_port( + const boost::asio::ip::address& _address, std::uint16_t _port, + bool _reliable) const { + + bool is_required(is_protected_device(_address)); + + if (!is_required) { + return false; + } + + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + const auto found_address = sd_acceptance_rules_.find(_address); + if (found_address != sd_acceptance_rules_.end()) { + const auto found_reliability = found_address->second.second.find(_reliable); + if (found_reliability != found_address->second.second.end()) { + const auto its_range = boost::icl::interval<std::uint16_t>::closed(_port, _port); + + bool is_optional + = (found_reliability->second.first.find(its_range) + != found_reliability->second.first.end()); + + bool is_secure + = (found_reliability->second.second.find(its_range) + != found_reliability->second.second.end()); + + is_required = is_optional || is_secure; + } + } + + return is_required; +} + +bool configuration_impl::is_secure_port( + const boost::asio::ip::address& _address, std::uint16_t _port, + bool _reliable) const { + + bool is_secure(false); + + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + const auto found_address = sd_acceptance_rules_.find(_address); + if (found_address != sd_acceptance_rules_.end()) { + const auto found_reliability + = found_address->second.second.find(_reliable); + if (found_reliability != found_address->second.second.end()) { + const auto its_range + = boost::icl::interval<std::uint16_t>::closed(_port, _port); + return (found_reliability->second.second.find(its_range) + != found_reliability->second.second.end()); + } + } + + return is_secure; +} + +void configuration_impl::set_sd_acceptance_rule( + const boost::asio::ip::address &_address, + port_range_t _port_range, port_type_e _type, + const std::string &_path, bool _reliable, bool _enable, bool _default) { + + (void)_port_range; + (void)_type; + + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + + const auto its_optional_client = boost::icl::interval<std::uint16_t>::closed(30491, 30499); + const auto its_optional_client_spare = boost::icl::interval<std::uint16_t>::closed(30898, 30998); + const auto its_optional_server = boost::icl::interval<std::uint16_t>::closed(30501, 30599); + + const auto its_secure_client = boost::icl::interval<std::uint16_t>::closed(32491, 32499); + const auto its_secure_client_spare = boost::icl::interval<std::uint16_t>::closed(32898, 32998); + const auto its_secure_server = boost::icl::interval<std::uint16_t>::closed(32501, 32599); + + const bool rules_active = (sd_acceptance_rules_active_.find(_address) + != sd_acceptance_rules_active_.end()); + + const auto found_address = sd_acceptance_rules_.find(_address); + if (found_address != sd_acceptance_rules_.end()) { + if (found_address->second.first.length() > 0 + && found_address->second.first != _path) { + VSOMEIP_WARNING << __func__ << ": activation path for IP: " + << _address << " differ: " + << found_address->second.first << " vs. " << _path + << " will use: " << found_address->second.first; + } else { + found_address->second.first = _path; + } + const auto found_reliability = found_address->second.second.find(_reliable); + if (found_reliability != found_address->second.second.end()) { + if (_enable) { + // only insert full range interval if there are no other intervals + // configured + if (!_default || + (found_reliability->second.first.empty() + && found_reliability->second.second.empty())) { + found_reliability->second.first.add(its_optional_client); + found_reliability->second.first.add(its_optional_client_spare); + found_reliability->second.first.add(its_optional_server); + found_reliability->second.second.add(its_secure_client); + found_reliability->second.second.add(its_secure_client_spare); + found_reliability->second.second.add(its_secure_server); + if (!rules_active) { + sd_acceptance_rules_active_.insert(_address); + } + VSOMEIP_INFO << "ipsec:acceptance:" << _address + << ":" << (_reliable ? "tcp" : "udp") << ": using default ranges " + << found_reliability->second.first << " " + << found_reliability->second.second; + } else { + VSOMEIP_INFO << "ipsec:acceptance:" << _address + << ":" << (_reliable ? "tcp" : "udp") << ": using configured ranges " + << found_reliability->second.first << " " + << found_reliability->second.second; + } + } else { + found_reliability->second.first.erase(its_optional_client); + found_reliability->second.first.erase(its_optional_client_spare); + found_reliability->second.first.erase(its_optional_server); + found_reliability->second.second.erase(its_secure_client); + found_reliability->second.second.erase(its_secure_client_spare); + found_reliability->second.second.erase(its_secure_server); + if (found_reliability->second.first.empty() + && found_reliability->second.second.empty()) { + found_address->second.second.erase(found_reliability); + if (found_address->second.second.empty()) { + sd_acceptance_rules_.erase(found_address); + if (rules_active) {// no more rules for IP present + sd_acceptance_rules_active_.erase(_address); + } + } + } + } + } else if (_enable) { + boost::icl::interval_set<std::uint16_t> its_optional_default; + its_optional_default.add(its_optional_client); + its_optional_default.add(its_optional_client_spare); + its_optional_default.add(its_optional_server); + boost::icl::interval_set<std::uint16_t> its_secure_default; + its_secure_default.add(its_secure_client); + its_secure_default.add(its_secure_client_spare); + its_secure_default.add(its_secure_server); + + found_address->second.second.emplace( + std::make_pair(_reliable, + std::make_pair(its_optional_default, its_secure_default))); + if (!rules_active) { + sd_acceptance_rules_active_.insert(_address); + } + + const auto found_reliability = found_address->second.second.find(_reliable); + VSOMEIP_INFO << "ipsec:acceptance:" << _address + << ":" << (_reliable ? "tcp" : "udp") << ": using default ranges " + << found_reliability->second.first << " " + << found_reliability->second.second; + } + } else if (_enable) { + boost::icl::interval_set<std::uint16_t> its_optional_default; + its_optional_default.add(its_optional_client); + its_optional_default.add(its_optional_client_spare); + its_optional_default.add(its_optional_server); + boost::icl::interval_set<std::uint16_t> its_secure_default; + its_secure_default.add(its_secure_client); + its_secure_default.add(its_secure_client_spare); + its_secure_default.add(its_secure_server); + + sd_acceptance_rules_.emplace(std::make_pair(_address, + std::make_pair( + _path, + std::map< + bool, + std::pair< + boost::icl::interval_set<std::uint16_t>, + boost::icl::interval_set<std::uint16_t> + > + >({{ + _reliable, + std::make_pair(its_optional_default, its_secure_default) + }})))); + if (!rules_active) { + sd_acceptance_rules_active_.insert(_address); + } + + const auto found_address = sd_acceptance_rules_.find(_address); + if (found_address != sd_acceptance_rules_.end()) { + const auto found_reliability = found_address->second.second.find(_reliable); + if (found_reliability != found_address->second.second.end()) { + VSOMEIP_INFO << "ipsec:acceptance:" << _address + << ":" << (_reliable ? "tcp" : "udp") << ": using default ranges " + << found_reliability->second.first << " " + << found_reliability->second.second; + } + } + } +} + +configuration::sd_acceptance_rules_t configuration_impl::get_sd_acceptance_rules() { + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + return sd_acceptance_rules_; +} + +void configuration_impl::set_sd_acceptance_rules_active( + const boost::asio::ip::address& _address, bool _enable) { + std::lock_guard<std::mutex> its_lock(sd_acceptance_required_ips_mutex_); + if (_enable) { + sd_acceptance_rules_active_.insert(_address); + } else { + sd_acceptance_rules_active_.erase(_address); + } +} + +bool configuration_impl::is_secure_service(service_t _service, instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(secure_services_mutex_); + const auto its_service = secure_services_.find(_service); + if (its_service != secure_services_.end()) + return (its_service->second.find(_instance) != its_service->second.end()); + return false; +} + +int configuration_impl::get_udp_receive_buffer_size() const { + + return udp_receive_buffer_size_; +} + +bool configuration_impl::is_tp_client( + service_t _service, + instance_t _instance, + method_t _method) const { + + bool ret(false); + + const auto its_service + = find_service(_service, _instance); + + if (its_service) { + ret = (its_service->tp_client_config_.find(_method) + != its_service->tp_client_config_.end()); + } + + return ret; +} + +bool configuration_impl::is_tp_service( + service_t _service, + instance_t _instance, + method_t _method) const { + + bool ret(false); + const auto its_service + = find_service(_service, _instance); + if (its_service) { + ret = (its_service->tp_service_config_.find(_method) + != its_service->tp_service_config_.end()); + } + + return ret; +} + +void configuration_impl::get_tp_configuration( + service_t _service, instance_t _instance, method_t _method, + bool _is_client, + std::uint16_t &_max_segment_length, std::uint32_t &_separation_time) const { + + const auto its_info = find_service(_service, _instance); + if (its_info) { + if (_is_client) { + auto its_method = its_info->tp_client_config_.find(_method); + + // Note: The following two lines do not make sense now, + // but they will when TP configuration is reworked + if (its_method == its_info->tp_client_config_.end()) + its_method = its_info->tp_client_config_.find(ANY_METHOD); + + if (its_method != its_info->tp_client_config_.end()) { + _max_segment_length = its_method->second.first; + _separation_time = its_method->second.second; + return; + } + } else { + auto its_method = its_info->tp_service_config_.find(_method); + + // Note: The following two lines do not make sense now, + // but they will when TP configuration is reworked + if (its_method == its_info->tp_service_config_.end()) + its_method = its_info->tp_service_config_.find(ANY_METHOD); + + if (its_method != its_info->tp_service_config_.end()) { + _max_segment_length = its_method->second.first; + _separation_time = its_method->second.second; + return; + } + } + } + + // No configuration defined --> set default values + _max_segment_length = VSOMEIP_TP_MAX_SEGMENT_LENGTH_DEFAULT; + _separation_time = 0; +} + +std::uint32_t configuration_impl::get_shutdown_timeout() const { + return shutdown_timeout_; +} + +bool configuration_impl::log_statistics() const { + return log_statistics_; +} + +uint32_t configuration_impl::get_statistics_interval() const { + return statistics_interval_; +} + +uint32_t configuration_impl::get_statistics_min_freq() const { + return statistics_min_freq_; +} + +uint32_t configuration_impl::get_statistics_max_messages() const { + return statistics_max_messages_; +} + +uint8_t configuration_impl::get_max_remote_subscribers() const { + return max_remote_subscribers_; +} + +partition_id_t +configuration_impl::get_partition_id( + service_t _service, instance_t _instance) const { + + partition_id_t its_id(VSOMEIP_DEFAULT_PARTITION_ID); + + std::lock_guard<std::mutex> its_lock(partitions_mutex_); + auto find_service = partitions_.find(_service); + if (find_service != partitions_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + its_id = find_instance->second; + } + } + + return its_id; +} + +reliability_type_e +configuration_impl::get_reliability_type( + const boost::asio::ip::address &_reliable_address, + const uint16_t &_reliable_port, + const boost::asio::ip::address &_unreliable_address, + const uint16_t &_unreliable_port) const { + + if (_reliable_port != ILLEGAL_PORT + && _unreliable_port != ILLEGAL_PORT + && !_reliable_address.is_unspecified() + && !_unreliable_address.is_unspecified()) { + return reliability_type_e::RT_BOTH; + } else if (_unreliable_port != ILLEGAL_PORT + && !_unreliable_address.is_unspecified()) { + return reliability_type_e::RT_UNRELIABLE; + } else if (_reliable_port != ILLEGAL_PORT + && !_reliable_address.is_unspecified()) { + return reliability_type_e::RT_RELIABLE; + } + return reliability_type_e::RT_UNKNOWN; +} + +bool +configuration_impl::is_security_enabled() const { + + return is_security_enabled_; +} + +bool +configuration_impl::is_security_external() const { + + return is_security_external_; +} + +bool +configuration_impl::is_security_audit() const { + + return is_security_audit_; +} + +bool +configuration_impl::is_remote_access_allowed() const { + + return is_remote_access_allowed_; +} + +std::shared_ptr<policy_manager_impl> configuration_impl::get_policy_manager() const { + return policy_manager_; +} + +std::shared_ptr<security> configuration_impl::get_security() const { + return security_; +} + +} // namespace cfg +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_plugin_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_plugin_impl.cpp new file mode 100644 index 00000000000..cf84520b78d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/configuration/src/configuration_plugin_impl.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2019-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "../include/configuration_plugin_impl.hpp" +#include "../include/configuration_impl.hpp" + +VSOMEIP_PLUGIN(vsomeip_v3::configuration_plugin_impl) + +namespace vsomeip_v3 { + +configuration_plugin_impl::configuration_plugin_impl() + : plugin_impl("vsomeip-configuration-plugin", + VSOMEIP_CONFIG_PLUGIN_VERSION, + plugin_type_e::CONFIGURATION_PLUGIN) { +} + +configuration_plugin_impl::~configuration_plugin_impl() { +} + +std::shared_ptr<configuration> +configuration_plugin_impl::get_configuration(const std::string &_name, + const std::string &_path) { + + std::shared_ptr<cfg::configuration_impl> its_configuration; + std::scoped_lock its_lock(mutex_); + auto its_iterator = configurations_.find(_name); + if (its_iterator != configurations_.end()) { + its_configuration = its_iterator->second; + } else { + its_configuration = std::make_shared<cfg::configuration_impl>(_path); + its_configuration->load(_name); + configurations_[_name] = its_configuration; + } + + return its_configuration; +} + +bool configuration_plugin_impl::remove_configuration(const std::string & _name) { + std::scoped_lock its_lock(mutex_); + return configurations_.erase(_name) > 0; +} +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/buffer/buffer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/buffer/buffer.hpp new file mode 100644 index 00000000000..6788281729d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/buffer/buffer.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_BUFFER_HPP +#define VSOMEIP_V3_E2E_BUFFER_HPP + +#include <stdexcept> +#include <cstdint> +#include <ostream> +#include <vector> + +namespace vsomeip_v3 { + +using e2e_buffer = std::vector<uint8_t>; + +class buffer_view { + public: + buffer_view(const uint8_t *_data_ptr, size_t _data_length) + : data_ptr_(_data_ptr), data_length_(_data_length) { + } + + buffer_view(const e2e_buffer &_buffer) + : data_ptr_(_buffer.data()), data_length_(_buffer.size()) {} + + buffer_view(const e2e_buffer &_buffer, size_t _length) + : data_ptr_(_buffer.data()), data_length_(_length) { + } + + buffer_view(const e2e_buffer &_buffer, size_t _begin, size_t _end) + : data_ptr_(_buffer.data() + _begin), data_length_(_end - _begin) { + } + + const uint8_t *begin(void) const { return data_ptr_; } + + const uint8_t *end(void) const { return data_ptr_ + data_length_; } + + size_t data_length(void) const { return data_length_; } + +private: + const uint8_t *data_ptr_; + size_t data_length_; +}; + +std::ostream &operator<<(std::ostream &_os, const e2e_buffer &_buffer); + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_BUFFER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/crc/crc.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/crc/crc.hpp new file mode 100644 index 00000000000..ac8e448f255 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/crc/crc.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_CRC_HPP +#define VSOMEIP_V3_E2E_CRC_HPP + +#include <cstdint> +#include "../buffer/buffer.hpp" + +namespace vsomeip_v3 { + +class e2e_crc { + public: + static uint8_t calculate_profile_01(buffer_view _buffer_view, + const uint8_t _start_value = 0x00U); + static uint32_t calculate_profile_04(buffer_view _buffer_view, + const uint32_t _start_value = 0x00000000U); + static uint16_t calculate_profile_05(buffer_view _buffer_view, + const uint16_t _start_value = 0xFFFFU); + static uint64_t calculate_profile_07(buffer_view _buffer_view, + const uint64_t _start_value = 0x0000000000000000U); + + static uint32_t calculate_profile_custom(buffer_view _buffer_view); + + private: + static const uint8_t lookup_table_profile_01_[256]; + static const uint32_t lookup_table_profile_04_[256]; + static const uint16_t lookup_table_profile_05_[256]; + static const uint64_t lookup_table_profile_07_[256]; + static const uint32_t lookup_table_profile_custom_[256]; + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_CRC_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp new file mode 100644 index 00000000000..51e42e17fea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROVIDER_HPP +#define VSOMEIP_V3_E2E_PROVIDER_HPP + +#include <string> +#include <memory> + +#include "../../buffer/buffer.hpp" +#include "../../e2exf/config.hpp" +#include "../../../../configuration/include/e2e.hpp" +#include "profile_interface/profile_interface.hpp" + +namespace vsomeip_v3 { +namespace e2e { + +class e2e_provider { +public: + virtual bool add_configuration(std::shared_ptr<cfg::e2e> config) = 0; + + virtual bool is_protected(e2exf::data_identifier_t id) const = 0; + virtual bool is_checked(e2exf::data_identifier_t id) const = 0; + + virtual std::size_t get_protection_base(e2exf::data_identifier_t _id) const = 0; + + virtual void protect(e2exf::data_identifier_t id, + e2e_buffer &_buffer, instance_t _instance) = 0; + virtual void check(e2exf::data_identifier_t id, + const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) = 0; +}; + +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROVIDER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp new file mode 100644 index 00000000000..631f87f29aa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROVIDER_IMPL_HPP +#define VSOMEIP_V3_E2E_PROVIDER_IMPL_HPP + +#include <map> +#include <memory> + +#include "e2e_provider.hpp" +#include "profile_interface/checker.hpp" +#include "profile_interface/protector.hpp" + +#include "../../../../../interface/vsomeip/export.hpp" +#include "../../../../../interface/vsomeip/plugin.hpp" + +namespace vsomeip_v3 { +namespace e2e { + +class e2e_provider_impl : + public e2e_provider, + public plugin_impl<e2e_provider_impl>, + public std::enable_shared_from_this<e2e_provider_impl> { +public: + VSOMEIP_EXPORT e2e_provider_impl(); + VSOMEIP_EXPORT ~e2e_provider_impl(); + + VSOMEIP_EXPORT bool add_configuration(std::shared_ptr<cfg::e2e> config) override; + + VSOMEIP_EXPORT bool is_protected(e2exf::data_identifier_t id) const override; + VSOMEIP_EXPORT bool is_checked(e2exf::data_identifier_t id) const override; + + VSOMEIP_EXPORT std::size_t get_protection_base(e2exf::data_identifier_t _id) const override; + + VSOMEIP_EXPORT void protect(e2exf::data_identifier_t id, + e2e_buffer &_buffer, instance_t _instance) override; + VSOMEIP_EXPORT void check(e2exf::data_identifier_t id, + const e2e_buffer &_buffer, instance_t _instance, + profile_interface::check_status_t &_generic_check_status) override; + +private: + std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::protector>> custom_protectors_; + std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::checker>> custom_checkers_; + std::map<e2exf::data_identifier_t, std::size_t> custom_bases_; + + template<typename config_t> + config_t make_e2e_profile_config(const std::shared_ptr<cfg::e2e>& config); + + template<typename config_t, typename checker_t, typename protector_t> + void process_e2e_profile(std::shared_ptr<cfg::e2e> config) { + const e2exf::data_identifier_t data_identifier = {config->service_id, config->event_id}; + config_t profile_config = make_e2e_profile_config<config_t>(config); + + std::shared_ptr<e2e::profile_interface::checker> checker; + if ((config->variant == "checker") || (config->variant == "both")) { + custom_checkers_[data_identifier] = std::make_shared<checker_t>(profile_config); + } + + std::shared_ptr<e2e::profile_interface::protector> protector; + if ((config->variant == "protector") || (config->variant == "both")) { + custom_protectors_[data_identifier] = std::make_shared<protector_t>(profile_config); + } + + custom_bases_[data_identifier] = profile_config.base_; + } +}; + +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROVIDER_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp new file mode 100644 index 00000000000..8f97113e03f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE01_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE01_CHECKER_HPP + +#include "../profile01/profile_01.hpp" +#include "../profile_interface/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +class profile_01_checker final : public e2e::profile_interface::checker { + +public: + profile_01_checker(void) = delete; + + // [SWS_E2E_00389] initialize state + explicit profile_01_checker(const profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + profile_config config_; + std::mutex check_mutex_; + +}; + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE01_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp new file mode 100644 index 00000000000..097d9f569ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE01_PROFILE01_HPP +#define VSOMEIP_V3_E2E_PROFILE01_PROFILE01_HPP + +#include <cstdint> + +#include <vsomeip/defines.hpp> + +#include "../../../buffer/buffer.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +struct profile_config; + +class profile_01 { + public: + static uint8_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); + + static bool is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer); +}; + +// [SWS_E2E_00200] +enum class p01_data_id_mode : uint8_t {E2E_P01_DATAID_BOTH, E2E_P01_DATAID_ALT, E2E_P01_DATAID_LOW, E2E_P01_DATAID_NIBBLE}; + +struct profile_config { + profile_config() = delete; + + profile_config(uint16_t _crc_offset, uint16_t _data_id, + p01_data_id_mode _data_id_mode, uint16_t _data_length, + uint16_t _counter_offset, uint16_t _data_id_nibble_offset) + + : crc_offset_(_crc_offset), data_id_(_data_id), + data_id_mode_(_data_id_mode), data_length_(_data_length), + counter_offset_(_counter_offset), + data_id_nibble_offset_(_data_id_nibble_offset), + base_(VSOMEIP_FULL_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + // [SWS_E2E_00018] + uint16_t crc_offset_; + uint16_t data_id_; + p01_data_id_mode data_id_mode_; + uint16_t data_length_; + uint16_t counter_offset_; + uint16_t data_id_nibble_offset_; + + // SOME/IP base + size_t base_; +}; + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE01_PROFILE01_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp new file mode 100644 index 00000000000..7e37993094e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE01_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE01_PROTECTOR_HPP + +#include <mutex> + +#include "../profile01/profile_01.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) : config_(_config), counter_(0) {}; + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + + void write_counter(e2e_buffer &_buffer); + + void write_data_id(e2e_buffer &_buffer); + + void write_crc(e2e_buffer &_buffer, uint8_t _computed_crc); + + void increment_counter(void); + +private: + profile_config config_; + uint8_t counter_; + std::mutex protect_mutex_; +}; + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE01_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp new file mode 100644 index 00000000000..2ed3ebdc914 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP + +#include <map> + +#include "../profile04/profile_04.hpp" +#include "../profile_interface/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +class profile_04_checker final : public e2e::profile_interface::checker { + +public: + profile_04_checker(void) = delete; + + // [SWS_E2E_00389] initialize state + explicit profile_04_checker(const profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + bool verify_input(const e2e_buffer &_buffer) const; + bool verify_counter(instance_t _instance, uint16_t _received_counter); + + bool read_16(const e2e_buffer &_buffer, uint16_t &_data, size_t _index) const; + bool read_32(const e2e_buffer &_buffer, uint32_t &_data, size_t _index) const; + + std::mutex check_mutex_; + + profile_config config_; + std::map<instance_t, uint16_t> counter_; +}; + +} // namespace profile_04 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp new file mode 100644 index 00000000000..11a7ee7e179 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP +#define VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP + +#include <cstdint> + +#include <vsomeip/defines.hpp> + +#include "../../../buffer/buffer.hpp" + +// The MSB of the dataID is the instance identifier. +// Therefore, the instance identifier must fit into a single byte. +#define VSOMEIP_E2E_PROFILE04_MAX_INSTANCE 0x00ff + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +struct profile_config; + +class profile_04 { +public: + static uint32_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); +}; + +// [SWS_E2E_00200] +struct profile_config { + profile_config() = delete; + + profile_config(uint32_t _data_id, size_t _offset, + size_t _min_data_length, size_t _max_data_length, + uint16_t _max_delta_counter) + : data_id_(_data_id), offset_(_offset), + min_data_length_(_min_data_length), max_data_length_(_max_data_length), + max_delta_counter_(_max_delta_counter), + base_(VSOMEIP_SOMEIP_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + // [SWS_E2E_00334] + uint32_t data_id_; + size_t offset_; // This must be configured in bit but as a multiple of 8. + // As we must use it as an index, we do the math once at + // configuration time and use the correct data type here. + // Thus, this value is always the byte where the CRC starts. + size_t min_data_length_; + size_t max_data_length_; + uint16_t max_delta_counter_; + + // SOME/IP base + size_t base_; +}; + +} // namespace profile_04 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp new file mode 100644 index 00000000000..eab0a9a7a7b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP + +#include <map> +#include <mutex> + +#include "../profile04/profile_04.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) + : config_(_config) {} + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + bool verify_inputs(e2e_buffer &_buffer); + uint16_t get_counter(instance_t _instance) const; + void increment_counter(instance_t _instance); + + void write_16(e2e_buffer &_buffer, uint16_t _data, size_t _index); + void write_32(e2e_buffer &_buffer, uint32_t _data, size_t _index); + +private: + profile_config config_; + std::map<instance_t, uint16_t> counter_; + std::mutex protect_mutex_; +}; + +} // namespace profile_04 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp new file mode 100644 index 00000000000..3805132b0bf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP + +#include <map> + +#include "../profile05/profile_05.hpp" +#include "../profile_interface/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +class profile_05_checker final : public e2e::profile_interface::checker { + +public: + profile_05_checker(void) = delete; + + // [SWS_E2E_00389] initialize state + explicit profile_05_checker(const profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + bool verify_input(const e2e_buffer &_buffer) const; + bool verify_counter(instance_t _instance, uint8_t _received_counter); + + bool read_8(const e2e_buffer &_buffer, uint8_t &_data, size_t _index) const; + bool read_16(const e2e_buffer &_buffer, uint16_t &_data, size_t _index) const; + + std::mutex check_mutex_; + + profile_config config_; + std::map<instance_t, uint8_t> counter_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp new file mode 100644 index 00000000000..92d5a26eb03 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP +#define VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP + +#include <cstdint> + +#include <vsomeip/defines.hpp> + +#include "../../../buffer/buffer.hpp" + +// The MSB of the dataID is the instance identifier. +// Therefore, the instance identifier must fit into a single byte. +#define VSOMEIP_E2E_PROFILE05_MAX_INSTANCE 0x00ff + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +struct profile_config; + +class profile_05 { +public: + static uint16_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); + + static bool is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer); +}; + +struct profile_config { + profile_config() = delete; + + profile_config(uint32_t _data_id, uint16_t _data_length, + size_t _offset, uint16_t _max_delta_counter) + + : data_id_(_data_id), data_length_(_data_length), + offset_(_offset), max_delta_counter_(_max_delta_counter), + base_(VSOMEIP_SOMEIP_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + uint32_t data_id_; + uint16_t data_length_; + size_t offset_; // This must be configured in bit but as a multiple of 8. + // As we must use it as an index, we do the math once at + // configuration time and use the correct data type here. + // Thus, this value is always the byte where the CRC starts. + uint16_t max_delta_counter_; + + // SOME/IP base + size_t base_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp new file mode 100644 index 00000000000..a659685182b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP + +#include <map> +#include <mutex> + +#include "../profile05/profile_05.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) + : config_(_config) {} + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + bool verify_inputs(e2e_buffer &_buffer); + uint8_t get_counter(instance_t _instance) const; + void increment_counter(instance_t _instance); + + void write_counter(e2e_buffer &_buffer, uint8_t _data, size_t _index); + void write_crc(e2e_buffer &_buffer, uint16_t _data, size_t _index); + +private: + profile_config config_; + std::map<instance_t, uint8_t> counter_; + std::mutex protect_mutex_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/checker.hpp new file mode 100644 index 00000000000..6aa9a887abf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/checker.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE07_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE07_CHECKER_HPP + +#include <map> + +#include "../profile07/profile_07.hpp" +#include "../profile_interface/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +class profile_07_checker final : public e2e::profile_interface::checker { + +public: + profile_07_checker(void) = delete; + + // [SWS_E2E_00389] initialize state + explicit profile_07_checker(const profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + bool verify_input(const e2e_buffer &_buffer) const; + bool verify_counter(instance_t _instance, uint32_t _received_counter); + + bool read_32(const e2e_buffer &_buffer, uint32_t &_data, size_t _index) const; + bool read_64(const e2e_buffer &_buffer, uint64_t &_data, size_t _index) const; + + std::mutex check_mutex_; + + profile_config config_; + std::map<instance_t, uint32_t> counter_; +}; + +} // namespace profile_07 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE07_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/profile_07.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/profile_07.hpp new file mode 100644 index 00000000000..86c909fd15b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/profile_07.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE07_PROFILE07_HPP +#define VSOMEIP_V3_E2E_PROFILE07_PROFILE07_HPP + +#include <cstdint> + +#include <vsomeip/defines.hpp> + +#include "../../../buffer/buffer.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +const uint8_t PROFILE_07_SIZE_OFFSET = 8; +const uint8_t PROFILE_07_COUNTER_OFFSET = 12; +const uint8_t PROFILE_07_DATAID_OFFSET = 16; +const uint8_t PROFILE_07_CRC_OFFSET = 0; + +struct profile_config; + +class profile_07 { +public: + static uint64_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); +}; + +// [SWS_E2E_00200] +struct profile_config { + profile_config() = delete; + + profile_config(uint32_t _data_id, size_t _offset, + size_t _min_data_length, size_t _max_data_length, + uint32_t _max_delta_counter) + : data_id_(_data_id), offset_(_offset), + min_data_length_(_min_data_length), max_data_length_(_max_data_length), + max_delta_counter_(_max_delta_counter), + base_(VSOMEIP_SOMEIP_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + uint32_t data_id_; + size_t offset_; // This must be configured in bit but as a multiple of 8. + // As we must use it as an index, we do the math once at + // configuration time and use the correct data type here. + // Thus, this value is always the byte where the CRC starts. + size_t min_data_length_; + size_t max_data_length_; + uint32_t max_delta_counter_; + + // SOME/IP base + size_t base_; +}; + +} // namespace profile_07 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE07_PROFILE07_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/protector.hpp new file mode 100644 index 00000000000..90ea990d935 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile07/protector.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE07_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE07_PROTECTOR_HPP + +#include <map> +#include <mutex> + +#include "../profile07/profile_07.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) + : config_(_config) {} + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + bool verify_inputs(e2e_buffer &_buffer); + uint32_t get_counter(instance_t _instance) const; + void increment_counter(instance_t _instance); + + void write_32(e2e_buffer &_buffer, uint32_t _data, size_t _index); + void write_64(e2e_buffer &_buffer, uint64_t _data, size_t _index); + +private: + profile_config config_; + std::map<instance_t, uint32_t> counter_; + std::mutex protect_mutex_; +}; + +} // namespace profile_07 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE07_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp new file mode 100644 index 00000000000..94d54564e93 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_CUSTOM_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE_CUSTOM_CHECKER_HPP + +#include "../profile_custom/profile_custom.hpp" +#include "../profile_interface/checker.hpp" +#include <mutex> + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +class profile_custom_checker final + : public e2e::profile_interface::checker { + +public: + profile_custom_checker(void) = delete; + + explicit profile_custom_checker(const e2e::profile_custom::profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + uint32_t read_crc(const e2e_buffer &_buffer) const; + +private: + profile_config config_; + std::mutex check_mutex_; + +}; + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_CUSTOM_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp new file mode 100644 index 00000000000..0a97ff1b1b2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROFILE_CUSTOM_HPP +#define VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROFILE_CUSTOM_HPP + +#include <cstdint> + +#include <vsomeip/defines.hpp> + +#include "../../../buffer/buffer.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +struct profile_config; + +class profile_custom { + public: + static uint32_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); + + static bool is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer); +}; + +struct profile_config { + profile_config() = delete; + + profile_config(uint16_t _crc_offset) + : crc_offset_(_crc_offset), + base_(VSOMEIP_FULL_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + uint16_t crc_offset_; + size_t base_; +}; + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROFILE_CUSTOM_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp new file mode 100644 index 00000000000..2396b5ad046 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROTECTOR_HPP + +#include <mutex> +#include "../profile_custom/profile_custom.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) : config_(_config){}; + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + + void write_crc(e2e_buffer &_buffer, uint32_t _computed_crc); + +private: + profile_config config_; + std::mutex protect_mutex_; +}; + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp new file mode 100644 index 00000000000..1bdf44744d7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_INTERFACE_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE_INTERFACE_CHECKER_HPP + +#include <mutex> + +#include <vsomeip/primitive_types.hpp> + +#include "../profile_interface/profile_interface.hpp" +#include "../../../buffer/buffer.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_interface { + +class checker : public profile_interface { +public: + virtual void check(const e2e_buffer &_buffer, instance_t _instance, + check_status_t &_generic_check_status) = 0; +}; + +} // namespace profile_interface +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_INTERFACE_CHECKER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp new file mode 100644 index 00000000000..02c4bbe1f67 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROFILE_INTERFACE_HPP +#define VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROFILE_INTERFACE_HPP + +#include <cstdint> + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_interface { + +typedef uint8_t check_status_t; +enum generic_check_status : check_status_t { E2E_OK, E2E_WRONG_CRC, E2E_ERROR}; + + +class profile_interface { +public: + virtual ~profile_interface() {} +}; + +} // namespace profile_interface +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROFILE_INTERFACE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp new file mode 100644 index 00000000000..20c63d52757 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROTECTOR_HPP + +#include <vsomeip/primitive_types.hpp> + +#include "../../../buffer/buffer.hpp" +#include "../profile_interface/profile_interface.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_interface { + +class protector : public profile_interface { +public: + virtual void protect(e2e_buffer &_buffer, + instance_t _instance) = 0; +}; + +} // namespace profile_interface +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROTECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2exf/config.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2exf/config.hpp new file mode 100644 index 00000000000..9c10504f855 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/include/e2exf/config.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2EXF_CONFIG_HPP +#define VSOMEIP_V3_E2EXF_CONFIG_HPP + +#include <vsomeip/primitive_types.hpp> +#include "../e2e/profile/profile_interface/checker.hpp" +#include "../e2e/profile/profile_interface/protector.hpp" + +#include <memory> +#include <map> + +namespace vsomeip_v3 { +namespace e2exf { + +using data_identifier_t = std::pair<service_t, event_t>; + +std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier_t &_data_identifier); + +} // namespace e2exf +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2EXF_CONFIG_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/buffer/buffer.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/buffer/buffer.cpp new file mode 100644 index 00000000000..6d82622bf7f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/buffer/buffer.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../e2e_protection/include/buffer/buffer.hpp" +#include <iomanip> + +namespace vsomeip_v3 { + +std::ostream &operator<<(std::ostream &_os, const e2e_buffer &_buffer) { + for (auto b : _buffer) { + if (isupper(b)) { + _os << b; + } else { + _os << "[" << std::setfill('0') << std::setw(2) << std::hex << (uint32_t)b << std::dec << "]"; + } + } + return _os; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/crc/crc.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/crc/crc.cpp new file mode 100644 index 00000000000..89b70d0e509 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/crc/crc.cpp @@ -0,0 +1,305 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../include/crc/crc.hpp" +#include <iostream> +#include <string> +#include <iomanip> + +namespace vsomeip_v3 { + +/** + * Calculates the crc over the provided range. + * + * @param begin Constant iterator pointing to begin of the range. + * @param end Constant iterator pointing to end of the range. + * @param startValue The crc value from previous call. + * @return The calculated crc value. + * + * Parameters of the CRC: + * - Width = 8 + * - Poly = 0x1D + * - XorIn = 0xFF + * - ReflectIn = false + * - XorOut = 0xFF + * - ReflectOut = false + * - Algorithm = table-driven + */ +uint8_t e2e_crc::calculate_profile_01(buffer_view _buffer_view, const uint8_t _start_value) { + uint8_t crc = _start_value ^ 0xFFU; + for (uint8_t byte : _buffer_view) { + /* + * XXX Right-shifting 8 bits on uint8_t results in 0 every time. + * It is, quintessentially, shifting all bits into the void. + */ + crc = static_cast<uint8_t>(lookup_table_profile_01_[static_cast<uint8_t>((byte) ^ crc)]/* ^ (crc >> 8U)*/); + } + crc = crc ^ 0xFFU; + return crc; +} + +const uint8_t e2e_crc::lookup_table_profile_01_[256] = { + 0x00U, 0x1DU, 0x3AU, 0x27U, 0x74U, 0x69U, 0x4EU, 0x53U, 0xE8U, 0xF5U, 0xD2U, 0xCFU, 0x9CU, 0x81U, 0xA6U, 0xBBU, + 0xCDU, 0xD0U, 0xF7U, 0xEAU, 0xB9U, 0xA4U, 0x83U, 0x9EU, 0x25U, 0x38U, 0x1FU, 0x02U, 0x51U, 0x4CU, 0x6BU, 0x76U, + 0x87U, 0x9AU, 0xBDU, 0xA0U, 0xF3U, 0xEEU, 0xC9U, 0xD4U, 0x6FU, 0x72U, 0x55U, 0x48U, 0x1BU, 0x06U, 0x21U, 0x3CU, + 0x4AU, 0x57U, 0x70U, 0x6DU, 0x3EU, 0x23U, 0x04U, 0x19U, 0xA2U, 0xBFU, 0x98U, 0x85U, 0xD6U, 0xCBU, 0xECU, 0xF1U, + 0x13U, 0x0EU, 0x29U, 0x34U, 0x67U, 0x7AU, 0x5DU, 0x40U, 0xFBU, 0xE6U, 0xC1U, 0xDCU, 0x8FU, 0x92U, 0xB5U, 0xA8U, + 0xDEU, 0xC3U, 0xE4U, 0xF9U, 0xAAU, 0xB7U, 0x90U, 0x8DU, 0x36U, 0x2BU, 0x0CU, 0x11U, 0x42U, 0x5FU, 0x78U, 0x65U, + 0x94U, 0x89U, 0xAEU, 0xB3U, 0xE0U, 0xFDU, 0xDAU, 0xC7U, 0x7CU, 0x61U, 0x46U, 0x5BU, 0x08U, 0x15U, 0x32U, 0x2FU, + 0x59U, 0x44U, 0x63U, 0x7EU, 0x2DU, 0x30U, 0x17U, 0x0AU, 0xB1U, 0xACU, 0x8BU, 0x96U, 0xC5U, 0xD8U, 0xFFU, 0xE2U, + 0x26U, 0x3BU, 0x1CU, 0x01U, 0x52U, 0x4FU, 0x68U, 0x75U, 0xCEU, 0xD3U, 0xF4U, 0xE9U, 0xBAU, 0xA7U, 0x80U, 0x9DU, + 0xEBU, 0xF6U, 0xD1U, 0xCCU, 0x9FU, 0x82U, 0xA5U, 0xB8U, 0x03U, 0x1EU, 0x39U, 0x24U, 0x77U, 0x6AU, 0x4DU, 0x50U, + 0xA1U, 0xBCU, 0x9BU, 0x86U, 0xD5U, 0xC8U, 0xEFU, 0xF2U, 0x49U, 0x54U, 0x73U, 0x6EU, 0x3DU, 0x20U, 0x07U, 0x1AU, + 0x6CU, 0x71U, 0x56U, 0x4BU, 0x18U, 0x05U, 0x22U, 0x3FU, 0x84U, 0x99U, 0xBEU, 0xA3U, 0xF0U, 0xEDU, 0xCAU, 0xD7U, + 0x35U, 0x28U, 0x0FU, 0x12U, 0x41U, 0x5CU, 0x7BU, 0x66U, 0xDDU, 0xC0U, 0xE7U, 0xFAU, 0xA9U, 0xB4U, 0x93U, 0x8EU, + 0xF8U, 0xE5U, 0xC2U, 0xDFU, 0x8CU, 0x91U, 0xB6U, 0xABU, 0x10U, 0x0DU, 0x2AU, 0x37U, 0x64U, 0x79U, 0x5EU, 0x43U, + 0xB2U, 0xAFU, 0x88U, 0x95U, 0xC6U, 0xDBU, 0xFCU, 0xE1U, 0x5AU, 0x47U, 0x60U, 0x7DU, 0x2EU, 0x33U, 0x14U, 0x09U, + 0x7FU, 0x62U, 0x45U, 0x58U, 0x0BU, 0x16U, 0x31U, 0x2CU, 0x97U, 0x8AU, 0xADU, 0xB0U, 0xE3U, 0xFEU, 0xD9U, 0xC4U +}; + +/** +* Calculates the CRC over the provided range. +* +* @param begin Constant iterator pointing to begin of the range. +* @param end Constant iterator pointing to end of the range. +* @param startValue The CRC value from previous call. +* @return The calculated CRC value. +* +* Parameters of the CRC: +* - Width = 32 +* - Poly = 0xF4ACFB13 +* - XorIn = 0xFFFFFFFF +* - ReflectIn = true +* - XorOut = 0xFFFFFFFF +* - ReflectOut = true +*/ +uint32_t e2e_crc::calculate_profile_04(buffer_view _buffer_view, const uint32_t _start_value) { + + uint32_t crc = (_start_value ^ 0xFFFFFFFFU); + + for (uint8_t byte : _buffer_view) + crc = lookup_table_profile_04_[static_cast<uint8_t>(byte ^ crc)] ^ (crc >> 8U); + + return (crc ^ 0xFFFFFFFFU); +} + +const uint32_t e2e_crc::lookup_table_profile_04_[256] = { + 0x00000000U, 0x30850FF5U, 0x610A1FEAU, 0x518F101FU, 0xC2143FD4U, 0xF2913021U, 0xA31E203EU, 0x939B2FCBU, + 0x159615F7U, 0x25131A02U, 0x749C0A1DU, 0x441905E8U, 0xD7822A23U, 0xE70725D6U, 0xB68835C9U, 0x860D3A3CU, + 0x2B2C2BEEU, 0x1BA9241BU, 0x4A263404U, 0x7AA33BF1U, 0xE938143AU, 0xD9BD1BCFU, 0x88320BD0U, 0xB8B70425U, + 0x3EBA3E19U, 0x0E3F31ECU, 0x5FB021F3U, 0x6F352E06U, 0xFCAE01CDU, 0xCC2B0E38U, 0x9DA41E27U, 0xAD2111D2U, + 0x565857DCU, 0x66DD5829U, 0x37524836U, 0x07D747C3U, 0x944C6808U, 0xA4C967FDU, 0xF54677E2U, 0xC5C37817U, + 0x43CE422BU, 0x734B4DDEU, 0x22C45DC1U, 0x12415234U, 0x81DA7DFFU, 0xB15F720AU, 0xE0D06215U, 0xD0556DE0U, + 0x7D747C32U, 0x4DF173C7U, 0x1C7E63D8U, 0x2CFB6C2DU, 0xBF6043E6U, 0x8FE54C13U, 0xDE6A5C0CU, 0xEEEF53F9U, + 0x68E269C5U, 0x58676630U, 0x09E8762FU, 0x396D79DAU, 0xAAF65611U, 0x9A7359E4U, 0xCBFC49FBU, 0xFB79460EU, + 0xACB0AFB8U, 0x9C35A04DU, 0xCDBAB052U, 0xFD3FBFA7U, 0x6EA4906CU, 0x5E219F99U, 0x0FAE8F86U, 0x3F2B8073U, + 0xB926BA4FU, 0x89A3B5BAU, 0xD82CA5A5U, 0xE8A9AA50U, 0x7B32859BU, 0x4BB78A6EU, 0x1A389A71U, 0x2ABD9584U, + 0x879C8456U, 0xB7198BA3U, 0xE6969BBCU, 0xD6139449U, 0x4588BB82U, 0x750DB477U, 0x2482A468U, 0x1407AB9DU, + 0x920A91A1U, 0xA28F9E54U, 0xF3008E4BU, 0xC38581BEU, 0x501EAE75U, 0x609BA180U, 0x3114B19FU, 0x0191BE6AU, + 0xFAE8F864U, 0xCA6DF791U, 0x9BE2E78EU, 0xAB67E87BU, 0x38FCC7B0U, 0x0879C845U, 0x59F6D85AU, 0x6973D7AFU, + 0xEF7EED93U, 0xDFFBE266U, 0x8E74F279U, 0xBEF1FD8CU, 0x2D6AD247U, 0x1DEFDDB2U, 0x4C60CDADU, 0x7CE5C258U, + 0xD1C4D38AU, 0xE141DC7FU, 0xB0CECC60U, 0x804BC395U, 0x13D0EC5EU, 0x2355E3ABU, 0x72DAF3B4U, 0x425FFC41U, + 0xC452C67DU, 0xF4D7C988U, 0xA558D997U, 0x95DDD662U, 0x0646F9A9U, 0x36C3F65CU, 0x674CE643U, 0x57C9E9B6U, + 0xC8DF352FU, 0xF85A3ADAU, 0xA9D52AC5U, 0x99502530U, 0x0ACB0AFBU, 0x3A4E050EU, 0x6BC11511U, 0x5B441AE4U, + 0xDD4920D8U, 0xEDCC2F2DU, 0xBC433F32U, 0x8CC630C7U, 0x1F5D1F0CU, 0x2FD810F9U, 0x7E5700E6U, 0x4ED20F13U, + 0xE3F31EC1U, 0xD3761134U, 0x82F9012BU, 0xB27C0EDEU, 0x21E72115U, 0x11622EE0U, 0x40ED3EFFU, 0x7068310AU, + 0xF6650B36U, 0xC6E004C3U, 0x976F14DCU, 0xA7EA1B29U, 0x347134E2U, 0x04F43B17U, 0x557B2B08U, 0x65FE24FDU, + 0x9E8762F3U, 0xAE026D06U, 0xFF8D7D19U, 0xCF0872ECU, 0x5C935D27U, 0x6C1652D2U, 0x3D9942CDU, 0x0D1C4D38U, + 0x8B117704U, 0xBB9478F1U, 0xEA1B68EEU, 0xDA9E671BU, 0x490548D0U, 0x79804725U, 0x280F573AU, 0x188A58CFU, + 0xB5AB491DU, 0x852E46E8U, 0xD4A156F7U, 0xE4245902U, 0x77BF76C9U, 0x473A793CU, 0x16B56923U, 0x263066D6U, + 0xA03D5CEAU, 0x90B8531FU, 0xC1374300U, 0xF1B24CF5U, 0x6229633EU, 0x52AC6CCBU, 0x03237CD4U, 0x33A67321U, + 0x646F9A97U, 0x54EA9562U, 0x0565857DU, 0x35E08A88U, 0xA67BA543U, 0x96FEAAB6U, 0xC771BAA9U, 0xF7F4B55CU, + 0x71F98F60U, 0x417C8095U, 0x10F3908AU, 0x20769F7FU, 0xB3EDB0B4U, 0x8368BF41U, 0xD2E7AF5EU, 0xE262A0ABU, + 0x4F43B179U, 0x7FC6BE8CU, 0x2E49AE93U, 0x1ECCA166U, 0x8D578EADU, 0xBDD28158U, 0xEC5D9147U, 0xDCD89EB2U, + 0x5AD5A48EU, 0x6A50AB7BU, 0x3BDFBB64U, 0x0B5AB491U, 0x98C19B5AU, 0xA84494AFU, 0xF9CB84B0U, 0xC94E8B45U, + 0x3237CD4BU, 0x02B2C2BEU, 0x533DD2A1U, 0x63B8DD54U, 0xF023F29FU, 0xC0A6FD6AU, 0x9129ED75U, 0xA1ACE280U, + 0x27A1D8BCU, 0x1724D749U, 0x46ABC756U, 0x762EC8A3U, 0xE5B5E768U, 0xD530E89DU, 0x84BFF882U, 0xB43AF777U, + 0x191BE6A5U, 0x299EE950U, 0x7811F94FU, 0x4894F6BAU, 0xDB0FD971U, 0xEB8AD684U, 0xBA05C69BU, 0x8A80C96EU, + 0x0C8DF352U, 0x3C08FCA7U, 0x6D87ECB8U, 0x5D02E34DU, 0xCE99CC86U, 0xFE1CC373U, 0xAF93D36CU, 0x9F16DC99U +}; + + +/** +* Calculates the CRC16 over the provided range. +*/ +uint16_t e2e_crc::calculate_profile_05(buffer_view _buffer_view, const uint16_t _start_value) { + const uint8_t * buffer = _buffer_view.begin(); + uint32_t buffer_length = (uint32_t)_buffer_view.data_length(); + uint16_t crc = _start_value; + + /* Process all data (byte wise) */ + for (uint32_t i = 0; i < buffer_length; ++i) { + /* Process one byte of data */ + crc = lookup_table_profile_05_[((uint8_t)(crc >> 8U)) ^ buffer[i]] ^ + ((uint16_t)(crc << 8U)); + } + + /* Specified final XOR value for CRC16 is 0, no need to actually xor anything here */ + return crc; +} + + +const uint16_t e2e_crc::lookup_table_profile_05_[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, + 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, + 0x9339U, 0x8318U, 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, 0x5485U, + 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, + 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, + 0x48C4U, 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, 0xA90AU, 0xB92BU, + 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, + 0xDBFDU, 0xCBDCU, 0xFBBFU, 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, + 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, + 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, + 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, 0x2E32U, 0x1E51U, 0x0E70U, + 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, + 0x9188U, 0x81A9U, 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, + 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, + 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, + 0x34E2U, 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, 0xC71DU, 0xD73CU, + 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xD94CU, 0xC96DU, 0xF90EU, 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, + 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, + 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, 0x1AD0U, 0x2AB3U, 0x3A92U, + 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, + 0x7C26U, 0x6C07U, 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, + 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, 0x9FF8U, + 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U +}; + + +/** +* Calculates the CRC over the provided range. +* +* @param begin Constant iterator pointing to begin of the range. +* @param end Constant iterator pointing to end of the range. +* @param startValue The CRC value from previous call. +* @return The calculated CRC value. +* +* Parameters of the CRC: +* - Width = 32 +* - Poly = 0x4C11DB7 +* - InitValue = 0xFFFFFFFF +* - ReflectIn = true +* - XorOut = 0xFFFFFFFF +* - ReflectOut = true +*/ +uint32_t e2e_crc::calculate_profile_custom(buffer_view _buffer_view) { + // InitValue + uint32_t crc = 0xFFFFFFFFU; + + for (uint8_t byte : _buffer_view) { + crc = lookup_table_profile_custom_[static_cast<uint8_t>(byte ^ crc)] ^ (crc >> 8U); + } + + // XorOut + crc = crc ^ 0xFFFFFFFFU; + return crc; +} + +const uint32_t e2e_crc::lookup_table_profile_custom_[256] = { + 0x00000000U, 0x77073096U, 0xEE0E612CU, 0x990951BAU, 0x076DC419U, 0x706AF48FU, 0xE963A535U, 0x9E6495A3U, + 0x0EDB8832U, 0x79DCB8A4U, 0xE0D5E91EU, 0x97D2D988U, 0x09B64C2BU, 0x7EB17CBDU, 0xE7B82D07U, 0x90BF1D91U, + 0x1DB71064U, 0x6AB020F2U, 0xF3B97148U, 0x84BE41DEU, 0x1ADAD47DU, 0x6DDDE4EBU, 0xF4D4B551U, 0x83D385C7U, + 0x136C9856U, 0x646BA8C0U, 0xFD62F97AU, 0x8A65C9ECU, 0x14015C4FU, 0x63066CD9U, 0xFA0F3D63U, 0x8D080DF5U, + 0x3B6E20C8U, 0x4C69105EU, 0xD56041E4U, 0xA2677172U, 0x3C03E4D1U, 0x4B04D447U, 0xD20D85FDU, 0xA50AB56BU, + 0x35B5A8FAU, 0x42B2986CU, 0xDBBBC9D6U, 0xACBCF940U, 0x32D86CE3U, 0x45DF5C75U, 0xDCD60DCFU, 0xABD13D59U, + 0x26D930ACU, 0x51DE003AU, 0xC8D75180U, 0xBFD06116U, 0x21B4F4B5U, 0x56B3C423U, 0xCFBA9599U, 0xB8BDA50FU, + 0x2802B89EU, 0x5F058808U, 0xC60CD9B2U, 0xB10BE924U, 0x2F6F7C87U, 0x58684C11U, 0xC1611DABU, 0xB6662D3DU, + 0x76DC4190U, 0x01DB7106U, 0x98D220BCU, 0xEFD5102AU, 0x71B18589U, 0x06B6B51FU, 0x9FBFE4A5U, 0xE8B8D433U, + 0x7807C9A2U, 0x0F00F934U, 0x9609A88EU, 0xE10E9818U, 0x7F6A0DBBU, 0x086D3D2DU, 0x91646C97U, 0xE6635C01U, + 0x6B6B51F4U, 0x1C6C6162U, 0x856530D8U, 0xF262004EU, 0x6C0695EDU, 0x1B01A57BU, 0x8208F4C1U, 0xF50FC457U, + 0x65B0D9C6U, 0x12B7E950U, 0x8BBEB8EAU, 0xFCB9887CU, 0x62DD1DDFU, 0x15DA2D49U, 0x8CD37CF3U, 0xFBD44C65U, + 0x4DB26158U, 0x3AB551CEU, 0xA3BC0074U, 0xD4BB30E2U, 0x4ADFA541U, 0x3DD895D7U, 0xA4D1C46DU, 0xD3D6F4FBU, + 0x4369E96AU, 0x346ED9FCU, 0xAD678846U, 0xDA60B8D0U, 0x44042D73U, 0x33031DE5U, 0xAA0A4C5FU, 0xDD0D7CC9U, + 0x5005713CU, 0x270241AAU, 0xBE0B1010U, 0xC90C2086U, 0x5768B525U, 0x206F85B3U, 0xB966D409U, 0xCE61E49FU, + 0x5EDEF90EU, 0x29D9C998U, 0xB0D09822U, 0xC7D7A8B4U, 0x59B33D17U, 0x2EB40D81U, 0xB7BD5C3BU, 0xC0BA6CADU, + 0xEDB88320U, 0x9ABFB3B6U, 0x03B6E20CU, 0x74B1D29AU, 0xEAD54739U, 0x9DD277AFU, 0x04DB2615U, 0x73DC1683U, + 0xE3630B12U, 0x94643B84U, 0x0D6D6A3EU, 0x7A6A5AA8U, 0xE40ECF0BU, 0x9309FF9DU, 0x0A00AE27U, 0x7D079EB1U, + 0xF00F9344U, 0x8708A3D2U, 0x1E01F268U, 0x6906C2FEU, 0xF762575DU, 0x806567CBU, 0x196C3671U, 0x6E6B06E7U, + 0xFED41B76U, 0x89D32BE0U, 0x10DA7A5AU, 0x67DD4ACCU, 0xF9B9DF6FU, 0x8EBEEFF9U, 0x17B7BE43U, 0x60B08ED5U, + 0xD6D6A3E8U, 0xA1D1937EU, 0x38D8C2C4U, 0x4FDFF252U, 0xD1BB67F1U, 0xA6BC5767U, 0x3FB506DDU, 0x48B2364BU, + 0xD80D2BDAU, 0xAF0A1B4CU, 0x36034AF6U, 0x41047A60U, 0xDF60EFC3U, 0xA867DF55U, 0x316E8EEFU, 0x4669BE79U, + 0xCB61B38CU, 0xBC66831AU, 0x256FD2A0U, 0x5268E236U, 0xCC0C7795U, 0xBB0B4703U, 0x220216B9U, 0x5505262FU, + 0xC5BA3BBEU, 0xB2BD0B28U, 0x2BB45A92U, 0x5CB36A04U, 0xC2D7FFA7U, 0xB5D0CF31U, 0x2CD99E8BU, 0x5BDEAE1DU, + 0x9B64C2B0U, 0xEC63F226U, 0x756AA39CU, 0x026D930AU, 0x9C0906A9U, 0xEB0E363FU, 0x72076785U, 0x05005713U, + 0x95BF4A82U, 0xE2B87A14U, 0x7BB12BAEU, 0x0CB61B38U, 0x92D28E9BU, 0xE5D5BE0DU, 0x7CDCEFB7U, 0x0BDBDF21U, + 0x86D3D2D4U, 0xF1D4E242U, 0x68DDB3F8U, 0x1FDA836EU, 0x81BE16CDU, 0xF6B9265BU, 0x6FB077E1U, 0x18B74777U, + 0x88085AE6U, 0xFF0F6A70U, 0x66063BCAU, 0x11010B5CU, 0x8F659EFFU, 0xF862AE69U, 0x616BFFD3U, 0x166CCF45U, + 0xA00AE278U, 0xD70DD2EEU, 0x4E048354U, 0x3903B3C2U, 0xA7672661U, 0xD06016F7U, 0x4969474DU, 0x3E6E77DBU, + 0xAED16A4AU, 0xD9D65ADCU, 0x40DF0B66U, 0x37D83BF0U, 0xA9BCAE53U, 0xDEBB9EC5U, 0x47B2CF7FU, 0x30B5FFE9U, + 0xBDBDF21CU, 0xCABAC28AU, 0x53B39330U, 0x24B4A3A6U, 0xBAD03605U, 0xCDD70693U, 0x54DE5729U, 0x23D967BFU, + 0xB3667A2EU, 0xC4614AB8U, 0x5D681B02U, 0x2A6F2B94U, 0xB40BBE37U, 0xC30C8EA1U, 0x5A05DF1BU, 0x2D02EF8DU +}; + +/** +* Calculates the CRC over the provided range. +* +* @param begin Constant iterator pointing to begin of the range. +* @param end Constant iterator pointing to end of the range. +* @param startValue The CRC value from previous call. +* @return The calculated CRC value. +* +* Parameters of the CRC: +* - Width = 64 +* - Poly = 0x42F0E1EBA9EA3693 +* - XorIn = 0xFFFFFFFFFFFFFFFF +* - ReflectIn = true +* - XorOut = 0xFFFFFFFFFFFFFFFF +* - ReflectOut = true +*/ +uint64_t e2e_crc::calculate_profile_07(buffer_view _buffer_view, const uint64_t _start_value) { + + uint64_t crc = (_start_value ^ 0xFFFFFFFFFFFFFFFFU); + + for (uint8_t byte : _buffer_view) + crc = lookup_table_profile_07_[static_cast<uint8_t>(byte ^ crc)] ^ (crc >> 8U); + + return (crc ^ 0xFFFFFFFFFFFFFFFFU); +} + +const uint64_t e2e_crc::lookup_table_profile_07_[256] = { + 0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, + 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, 0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E, 0xCBDB3E64AB761D61, + 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D, 0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, + 0x8A3A2631AE2DDA2F, 0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73, 0x056ED3E2F9E22447, 0xB6409F5CFA457B28, + 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9, 0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95, + 0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7, 0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, + 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4, 0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3, 0xBAD65A25A73D0BDC, + 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989, 0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, + 0x64B62BCAEBC387A1, 0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD, 0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, + 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C, 0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0, + 0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB, 0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, + 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1, 0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6, 0xD2F6B4961186FC89, + 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407, 0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, + 0x6820EEB3B6BBF755, 0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609, 0xE7741B60E174093D, 0x545A57DEE2D35652, + 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21, 0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D, + 0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F, 0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, + 0xC96C5795D7870F42, 0x7A421B2BD420502D, 0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A, 0xF516EEF883EFAE45, + 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10, 0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, + 0xB4F7F6AD86B4690B, 0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857, 0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, + 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536, 0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A, + 0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3, 0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, + 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9, 0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE, 0xF9802B81DE97DEB1, + 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD, 0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, + 0xB86133D4DBCC19FF, 0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3, 0x3735C6078C03E797, 0x841B8AB98FA4B8F8, + 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8, 0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4, + 0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6, 0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, + 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5, 0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2, 0xEC3B640A391F4FAD, + 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8, 0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, + 0x56ED3E2F9E224471, 0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D, 0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, + 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C, 0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910, + 0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B, 0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, + 0xDCD7181E300F9E5E, 0x6FF954A033A8C131, 0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036, 0xE0ADA17364673F59 +}; + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp new file mode 100644 index 00000000000..3a9643ee942 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp @@ -0,0 +1,243 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <sstream> + +#include <vsomeip/internal/logger.hpp> + +#include "../../../../e2e_protection/include/e2e/profile/e2e_provider_impl.hpp" + +#include "../../../../e2e_protection/include/e2e/profile/profile01/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile01/profile_01.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile01/protector.hpp" + +#include "../../../../e2e_protection/include/e2e/profile/profile04/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile04/profile_04.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile04/protector.hpp" + +#include "../../../../e2e_protection/include/e2e/profile/profile05/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile05/profile_05.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile05/protector.hpp" + +#include "../../../../e2e_protection/include/e2e/profile/profile_custom/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile_custom/protector.hpp" + +#include "../../../../e2e_protection/include/e2e/profile/profile07/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile07/profile_07.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile07/protector.hpp" + +namespace { + +template<typename value_t> +value_t read_value_from_config(const std::shared_ptr<vsomeip_v3::cfg::e2e> &_config, + const std::string &_name, + value_t _default_value = value_t()) { + + if (_config && _config->custom_parameters.count(_name)) { + + std::stringstream its_converter; + std::string its_value(_config->custom_parameters[_name]); + + if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') { + its_converter << std::hex << its_value; + } else { + its_converter << std::dec << its_value; + } + + value_t its_converted_value; + its_converter >> its_converted_value; + return its_converted_value; + } + + return _default_value; +} + +} // namespace + + +VSOMEIP_PLUGIN(vsomeip_v3::e2e::e2e_provider_impl) + +namespace vsomeip_v3 { +namespace e2e { + +e2e_provider_impl::e2e_provider_impl() + : plugin_impl("vsomeip e2e plugin", 1, plugin_type_e::APPLICATION_PLUGIN) +{ +} + +e2e_provider_impl::~e2e_provider_impl() +{ +} + +bool e2e_provider_impl::add_configuration(std::shared_ptr<cfg::e2e> config) +{ + if (config->profile == "CRC8" || config->profile == "P01") { + process_e2e_profile<profile01::profile_config, profile01::profile_01_checker, profile01::protector>(config); + return true; + } + + if (config->profile == "CRC32" || config->profile == "CSTM") { + process_e2e_profile<profile_custom::profile_config, profile_custom::profile_custom_checker, profile_custom::protector>(config); + return true; + } + + if (config->profile == "P04") { + process_e2e_profile<profile04::profile_config, profile04::profile_04_checker, profile04::protector>(config); + return true; + } + + if (config->profile == "P05") { + process_e2e_profile<profile05::profile_config, profile05::profile_05_checker, profile05::protector>(config); + return true; + } + + if (config->profile == "P07") { + process_e2e_profile<profile07::profile_config, profile07::profile_07_checker, profile07::protector>(config); + return true; + } + + return false; +} + +bool e2e_provider_impl::is_protected(e2exf::data_identifier_t id) const +{ + return custom_protectors_.count(id) > 0; +} + +bool e2e_provider_impl::is_checked(e2exf::data_identifier_t id) const +{ + return custom_checkers_.count(id) > 0; +} + +std::size_t e2e_provider_impl::get_protection_base(e2exf::data_identifier_t id) const +{ + const auto found_base = custom_bases_.find(id); + if (found_base != custom_bases_.end()) + return found_base->second; + + return 0; +} + +void e2e_provider_impl::protect(e2exf::data_identifier_t id, e2e_buffer &_buffer, + instance_t _instance) +{ + auto protector = custom_protectors_.find(id); + if(protector != custom_protectors_.end()) { + protector->second->protect(_buffer, _instance); + } +} + +void e2e_provider_impl::check(e2exf::data_identifier_t id, + const e2e_buffer &_buffer, instance_t _instance, + profile_interface::check_status_t &_generic_check_status) +{ + auto checker = custom_checkers_.find(id); + if(checker != custom_checkers_.end()) { + checker->second->check(_buffer, _instance, _generic_check_status); + } +} + +template<> +vsomeip_v3::e2e::profile01::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) { + uint16_t data_id = read_value_from_config<uint16_t>(_config, "data_id"); + uint16_t crc_offset = read_value_from_config<uint16_t>(_config, "crc_offset"); + uint16_t data_length = read_value_from_config<uint16_t>(_config, "data_length"); + + // counter field behind CRC8 + uint16_t counter_offset = read_value_from_config<uint16_t>(_config, "counter_offset", 8); + + // data id nibble behind 4 bit counter value + uint16_t data_id_nibble_offset = read_value_from_config<uint16_t>(_config, "data_id_nibble_offset", 12); + + e2e::profile01::p01_data_id_mode data_id_mode = + static_cast<e2e::profile01::p01_data_id_mode>( + read_value_from_config<uint16_t>(_config, "data_id_mode")); + + return e2e::profile01::profile_config(crc_offset, data_id, data_id_mode, + data_length, counter_offset, data_id_nibble_offset); +} + +template<> +vsomeip_v3::e2e::profile04::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) { + + uint32_t data_id = read_value_from_config<uint32_t>(_config, "data_id"); + + size_t offset = read_value_from_config<size_t>(_config, "crc_offset"); + if (offset % 8) + VSOMEIP_ERROR << "Offset in E2E P04 configuration must be multiple of 8" + " (" << offset << ")"; + offset /= 8; + + size_t min_data_length = read_value_from_config<size_t>(_config, + "min_data_length", 0); + + size_t max_data_length = read_value_from_config<size_t>(_config, + "max_data_length", size_t(0xffff)); + + uint16_t max_delta_counter = read_value_from_config<uint16_t>(_config, + "max_delta_counter", uint16_t(0xffff)); + + return e2e::profile04::profile_config(data_id, offset, + min_data_length, max_data_length, max_delta_counter); +} + +template<> +vsomeip_v3::e2e::profile05::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) { + + uint32_t data_id = read_value_from_config<uint32_t>(_config, "data_id"); + uint16_t data_length = read_value_from_config<uint16_t>(_config, "data_length"); + + size_t offset = read_value_from_config<size_t>(_config, "crc_offset"); + if (offset % 8) + VSOMEIP_ERROR << "Offset in E2E P05 configuration must be multiple of 8" + " (" << offset << ")"; + offset /= 8; + + uint16_t max_delta_counter = read_value_from_config<uint16_t>(_config, + "max_delta_counter", uint16_t(0xffff)); + + return e2e::profile05::profile_config(data_id, data_length, + offset, max_delta_counter); +} + +template<> +e2e::profile_custom::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e>& config) { + uint16_t crc_offset = read_value_from_config<uint16_t>(config, "crc_offset"); + return e2e::profile_custom::profile_config(crc_offset); +} + +template<> +vsomeip_v3::e2e::profile07::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) { + + uint32_t data_id = read_value_from_config<uint32_t>(_config, "data_id"); + + size_t offset = read_value_from_config<size_t>(_config, "crc_offset"); + if (offset % 8) + VSOMEIP_ERROR << "Offset in E2E P07 configuration must be multiple of 8" + " (" << offset << ")"; + offset /= 8; + + size_t min_data_length = read_value_from_config<size_t>(_config, + "min_data_length", 0); + + size_t max_data_length = read_value_from_config<size_t>(_config, + "max_data_length", size_t(0xffffffff)); + + uint32_t max_delta_counter = read_value_from_config<uint32_t>(_config, + "max_delta_counter", uint32_t(0xffffffff)); + + return e2e::profile07::profile_config(data_id, offset, + min_data_length, max_data_length, max_delta_counter); +} + +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp new file mode 100644 index 00000000000..d70dac6da66 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <algorithm> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile01/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +// [SWS_E2E_00196] +void profile_01_checker::check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + if (profile_01::is_buffer_length_valid(config_, _buffer)) { + uint8_t received_crc(0); + uint8_t calculated_crc(0); + received_crc = _buffer[config_.crc_offset_]; + calculated_crc = profile_01::compute_crc(config_, _buffer); + if (received_crc == calculated_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } else { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_INFO << std::hex << "E2E protection: CRC8 does not match: calculated CRC: " + << (uint32_t) calculated_crc << " received CRC: " << (uint32_t) received_crc; + } + } +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp new file mode 100644 index 00000000000..032bac033c9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/profile_01.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/e2e/profile/profile01/profile_01.hpp" +#include "../../../../include/crc/crc.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +uint8_t profile_01::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + uint8_t computed_crc = 0xFF; + e2e_buffer data_id_buffer; //(_data, _data+_size); + data_id_buffer.push_back((uint8_t) (_config.data_id_ >> 8)); // insert MSB + data_id_buffer.push_back((uint8_t) _config.data_id_); // insert LSB + + switch (_config.data_id_mode_) { + case p01_data_id_mode::E2E_P01_DATAID_BOTH: // CRC over 2 bytes + /* + * Two bytes are included in the CRC (double ID configuration) This is used in E2E variant 1A. + */ + // CRC = Crc_CalculateCRC8(Config->DataID, 1, 0xFF, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(data_id_buffer, 1, 2), 0xFF); //CRC over low byte of Data ID (LSB) + + // CRC = Crc_CalculateCRC8(Config->DataID >> 8, 1, CRC, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(data_id_buffer, 0, 1), computed_crc); //CRC over high byte of Data ID (MSB) + + break; + case p01_data_id_mode::E2E_P01_DATAID_LOW: // CRC over low byte only + /* + * Only the low byte is included, the high byte is never used. + * This is applicable if the IDs in a particular system are 8 bits + */ + // CRC = Crc_CalculateCRC8(Config->DataID, 1, 0xFF, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(data_id_buffer, 1, 2), 0xFF); //CRC over low byte of Data ID (LSB) + break; + + case p01_data_id_mode::E2E_P01_DATAID_ALT: + /* One of the two bytes byte is included, alternating high and low byte, + * depending on parity of the counter (alternating ID configuration). + * For an even counter, the low byte is included. + * For an odd counter, the high byte is included. + * This is used in E2E variant 1B. + * + if( counter % 2 == 0) { + // CRC = Crc_CalculateCRC8(Config->DataID, 1, 0xFF, FALSE) + computed_crc = crc::e2e_crc::calculate_profile_01(buffer::buffer_view(data_id_buffer, 1, 2), 0xFF); //CRC over low byte of Data ID (LSB) + } else { + // CRC = Crc_CalculateCRC8(Config->DataID >> 8, 1, 0xFF, FALSE) + computed_crc = crc::e2e_crc::calculate_profile_01(buffer::buffer_view(data_id_buffer, 0, 1), 0xFF); //CRC over high byte of Data ID (MSB) + } + */ + break; + + case p01_data_id_mode::E2E_P01_DATAID_NIBBLE: + /* + * The low byte is included in the implicit CRC calculation, + * the low nibble of the high byte is transmitted along with + * the data (i.e. it is explicitly included), the high nibble of + * the high byte is not used. This is applicable for the IDs + * up to 12 bits. This is used in E2E variant 1C. + */ + // CRC = Crc_CalculateCRC8(Config->DataID, 1, 0xFF, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(data_id_buffer, 1, 2), 0xFF); //CRC over low byte of Data ID (LSB) + + // CRC = Crc_CalculateCRC8 (0, 1, CRC, FALSE) + data_id_buffer.clear(); + data_id_buffer.push_back(0x00); + computed_crc = e2e_crc::calculate_profile_01(buffer_view(data_id_buffer, 0, 1), computed_crc); // CRC with 0x00 + break; + + default: + break; + } + + // Compute CRC over the area before the CRC (if CRC is not the first byte) + if (_config.crc_offset_ >= 1) { + // CRC = Crc_CalculateCRC8 (Data, (Config->CRCOffset / 8), CRC, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(_buffer, 0, _config.crc_offset_), computed_crc); + } + + // Compute the area after CRC, if CRC is not the last byte. Start with the byte after CRC, finish with the last byte of Data. + if ((_config.crc_offset_) < (_config.data_length_ / 8) - 1) { + // CRC = Crc_CalculateCRC8 (& Data[Config->CRCOffset/8 + 1], (Config->DataLength / 8 - Config->CRCOffset / 8 - 1), CRC, FALSE) + computed_crc = e2e_crc::calculate_profile_01(buffer_view(_buffer, static_cast<size_t>(_config.crc_offset_ + 1), _buffer.size()), computed_crc); + } + + // CRC = CRC ^ 0xFF + // To negate the last XOR 0xFF operation done on computed CRC by the last CalculateCRC8(), there is a XORing doneexternally by E2E Library + computed_crc = computed_crc ^ 0xFFU; + return computed_crc; +} + +/** @req [SWS_E2E_00356] */ +bool profile_01::is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer) { + return (((_config.data_length_ / 8) + 1U <= _buffer.size()) + && _config.crc_offset_ <= _buffer.size() + && _config.counter_offset_ / 8 <= _buffer.size() + && _config.data_id_nibble_offset_ / 8 <= _buffer.size()); +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp new file mode 100644 index 00000000000..0f514a02980 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile01/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile01 { + +/** @req [SWS_E2E_00195] */ +void protector::protect(e2e_buffer &_buffer, instance_t _instance) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(protect_mutex_); + + if (profile_01::is_buffer_length_valid(config_, _buffer)) { + // write the current Counter value in Data + write_counter(_buffer); + + // write DataID nibble in Data (E2E_P01_DATAID_NIBBLE) in Data + write_data_id(_buffer); + + // compute the CRC over DataID and Data + uint8_t computed_crc = profile_01::compute_crc(config_, _buffer); + // write CRC in Data + write_crc(_buffer, computed_crc); + + // increment the Counter (new value will be used in the next invocation of E2E_P01Protect()), + increment_counter(); + } +} + +/** @req [SRS_E2E_08528] */ +void protector::write_counter(e2e_buffer &_buffer) { + if (config_.counter_offset_ % 8 == 0) { + // write write counter value into low nibble + _buffer[config_.counter_offset_ / 8] = + static_cast<uint8_t>((_buffer[config_.counter_offset_ / 8] & 0xF0) | (counter_ & 0x0F)); + } else { + // write counter into high nibble + _buffer[config_.counter_offset_ / 8] = + static_cast<uint8_t>((_buffer[config_.counter_offset_ / 8] & 0x0F) | ((counter_ << 4) & 0xF0)); + } +} + +/** @req [SRS_E2E_08528] */ +void protector::write_data_id(e2e_buffer &_buffer) { + if (config_.data_id_mode_ == p01_data_id_mode::E2E_P01_DATAID_NIBBLE) { + if (config_.data_id_nibble_offset_ % 8 == 0) { + // write low nibble of high byte of Data ID + _buffer[config_.data_id_nibble_offset_ / 8] = + static_cast<uint8_t>((_buffer[config_.data_id_nibble_offset_ / 8] & 0xF0) | ((config_.data_id_ >> 8) & 0x0F)); + } else { + // write low nibble of high byte of Data ID + _buffer[config_.data_id_nibble_offset_ / 8] = + static_cast<uint8_t>((_buffer[config_.data_id_nibble_offset_ / 8] & 0x0F) | ((config_.data_id_ >> 4) & 0xF0)); + } + } +} + +/** @req [SRS_E2E_08528] */ +void protector::write_crc(e2e_buffer &_buffer, uint8_t _computed_crc) { + _buffer[config_.crc_offset_] = _computed_crc; +} + +/** @req [SWS_E2E_00075] */ +void protector::increment_counter(void) { + counter_ = static_cast<uint8_t>((counter_ + 1U) % 15); +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp new file mode 100644 index 00000000000..3e655f1d55e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "../../../../include/e2e/profile/profile04/checker.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +// [SWS_E2E_00355] +void profile_04_checker::check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + std::lock_guard<std::mutex> lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + if (_instance > VSOMEIP_E2E_PROFILE04_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 4 can only be used for instances [1-255]"; + return; + } + + /** @req [SWS_E2E_356] */ + if (verify_input(_buffer)) { + /** @req [SWS_E2E_357] */ + uint16_t its_received_length; + if (read_16(_buffer, its_received_length, 0)) { + /** @req [SWS_E2E_358] */ + uint16_t its_received_counter; + if (read_16(_buffer, its_received_counter, 2)) { + /** @req [SWS_E2E_359] */ + uint32_t its_received_data_id; + if (read_32(_buffer, its_received_data_id, 4)) { + /** @req [SWS_E2E_360] */ + uint32_t its_received_crc; + if (read_32(_buffer, its_received_crc, 8)) { + uint32_t its_crc = profile_04::compute_crc(config_, _buffer); + /** @req [SWS_E2E_361] */ + if (its_received_crc != its_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_ERROR << std::hex << "E2E P04 protection: CRC32 does not match: calculated CRC: " + << its_crc << " received CRC: " << its_received_crc; + } else { + uint32_t its_data_id(uint32_t(_instance) << 24 | config_.data_id_); + if (its_received_data_id == its_data_id + && static_cast<size_t>(its_received_length) == _buffer.size() + && verify_counter(_instance, its_received_counter)) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } + } + } + } + } + } + } +} + +bool +profile_04_checker::verify_input(const e2e_buffer &_buffer) const { + + auto its_length = _buffer.size(); + return (its_length >= config_.min_data_length_ + && its_length <= config_.max_data_length_); +} + +bool +profile_04_checker::verify_counter(instance_t _instance, uint16_t _received_counter) { + + uint16_t its_delta(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) { + uint16_t its_counter = find_counter->second; + if (its_counter < _received_counter) + its_delta = uint16_t(_received_counter - its_counter); + else + its_delta = uint16_t(uint16_t(0xffff) - its_counter + _received_counter); + } else { + counter_[_instance] = _received_counter; + } + + return (its_delta <= config_.max_delta_counter_); +} + +bool +profile_04_checker::read_16(const e2e_buffer &_buffer, + uint16_t &_data, size_t _index) const { + + _data = bithelper::read_uint16_be(&_buffer[config_.offset_ + _index]); + return true; +} + +bool +profile_04_checker::read_32(const e2e_buffer &_buffer, + uint32_t &_data, size_t _index) const { + + _data = bithelper::read_uint32_be(&_buffer[config_.offset_ + _index]); + return true; +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp new file mode 100644 index 00000000000..75800eeb9d4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/crc/crc.hpp" +#include "../../../../include/e2e/profile/profile04/profile_04.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +uint32_t profile_04::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + + buffer_view its_before(_buffer, _config.offset_ + 8); + uint32_t computed_crc = e2e_crc::calculate_profile_04(its_before); + + if (_config.offset_ + 12 < _buffer.size()) { + buffer_view its_after(_buffer, _config.offset_ + 12, _buffer.size()); + computed_crc = e2e_crc::calculate_profile_04(its_after, computed_crc); + } + + return computed_crc; +} + +} // namespace profile04 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp new file mode 100644 index 00000000000..e6abf84b927 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile04/protector.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile04 { + +/** @req [SWS_E2E_00195] */ +void +protector::protect(e2e_buffer &_buffer, instance_t _instance) { + std::lock_guard<std::mutex> lock(protect_mutex_); + + if (_instance > VSOMEIP_E2E_PROFILE04_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 4 can only be used for instances [1-255]"; + return; + } + + /** @req: [SWS_E2E_00363] */ + if (verify_inputs(_buffer)) { + + /** @req [SWS_E2E_00364] */ + bithelper::write_uint16_be(static_cast<uint16_t>(_buffer.size()), &_buffer[config_.offset_]); + + /** @req [SWS_E2E_00365] */ + bithelper::write_uint16_be(get_counter(_instance), &_buffer[config_.offset_ + 2]); + + /** @req [SWS_E2E_00366] */ + uint32_t its_data_id(uint32_t(_instance) << 24 | config_.data_id_); + bithelper::write_uint32_be(its_data_id, &_buffer[config_.offset_ + 4]); + + /** @req [SWS_E2E_00367] */ + uint32_t its_crc = profile_04::compute_crc(config_, _buffer); + + /** @req [SWS_E2E_0368] */ + bithelper::write_uint32_be(its_crc, &_buffer[config_.offset_ + 8]); + + /** @req [SWS_E2E_00369] */ + increment_counter(_instance); + } +} + +bool +protector::verify_inputs(e2e_buffer &_buffer) { + + return (_buffer.size() >= config_.min_data_length_ + && _buffer.size() <= config_.max_data_length_); +} + +uint16_t +protector::get_counter(instance_t _instance) const { + + uint16_t its_counter(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + its_counter = find_counter->second; + + return its_counter; +} + +void +protector::increment_counter(instance_t _instance) { + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + find_counter->second++; + else + counter_[_instance] = 1; +} + +} // namespace profile04 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp new file mode 100644 index 00000000000..964b73ac5e9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "../../../../include/e2e/profile/profile05/checker.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +void profile_05_checker::check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + if (_instance > VSOMEIP_E2E_PROFILE05_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 5 can only be used for instances [1-255]"; + return; + } + + if (profile_05::is_buffer_length_valid(config_, _buffer)) { + uint8_t its_received_counter; + if (read_8(_buffer, its_received_counter, 2)) { + uint16_t its_received_crc; + if (read_16(_buffer, its_received_crc, 0)) { + uint16_t its_crc = profile_05::compute_crc(config_, _buffer); + if (its_received_crc != its_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_ERROR << std::hex << "E2E P05 protection: CRC16 does not match: calculated CRC: " + << its_crc << " received CRC: " << its_received_crc; + } else { + if (verify_counter(_instance, its_received_counter)) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } + } + } + } + } +} + +bool +profile_05_checker::verify_counter(instance_t _instance, uint8_t _received_counter) { + + uint8_t its_delta(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) { + uint8_t its_counter = find_counter->second; + if (its_counter < _received_counter) + its_delta = uint8_t(_received_counter - its_counter); + else + its_delta = uint8_t(uint8_t(0xff) - its_counter + _received_counter); + } else { + counter_[_instance] = _received_counter; + } + + return (its_delta <= config_.max_delta_counter_); +} + +bool +profile_05_checker::read_8(const e2e_buffer &_buffer, + uint8_t &_data, size_t _index) const { + + _data = _buffer[config_.offset_ + _index]; + return true; +} + +bool +profile_05_checker::read_16(const e2e_buffer &_buffer, + uint16_t &_data, size_t _index) const { + + _data = bithelper::read_uint16_be(&_buffer[config_.offset_ + _index]); + return true; +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp new file mode 100644 index 00000000000..03efc444fbe --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/crc/crc.hpp" +#include "../../../../include/e2e/profile/profile05/profile_05.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +uint16_t profile_05::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + + static const int crcSize = sizeof(uint16_t); + + buffer_view its_before(_buffer, _config.offset_); + uint16_t computed_crc = e2e_crc::calculate_profile_05(its_before); + + if ((_config.offset_ + crcSize) < _buffer.size()) { + buffer_view its_after(_buffer, _config.offset_ + crcSize, _buffer.size()); + computed_crc = e2e_crc::calculate_profile_05(its_after, computed_crc); + } + + uint8_t dataId[2]; + dataId[0] = (_config.data_id_ >> 0) & 0xFF; + dataId[1] = (_config.data_id_ >> 8) & 0xFF; + buffer_view dataIdView(dataId, sizeof(dataId)); + + computed_crc = e2e_crc::calculate_profile_05(dataIdView, computed_crc); + + return computed_crc; +} + +bool profile_05::is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer) { + return ((_config.data_length_ / 8) + 1U <= _buffer.size()); +} +} // namespace profile05 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp new file mode 100644 index 00000000000..46843a6d400 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile05/protector.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +void protector::protect(e2e_buffer &_buffer, instance_t _instance) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(protect_mutex_); + + if (_instance > VSOMEIP_E2E_PROFILE05_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 5 can only be used for instances [1-255]"; + return; + } + + if (profile_05::is_buffer_length_valid(config_, _buffer)) { + // write the current Counter value in Data + write_counter(_buffer, get_counter(_instance), 2); + + // compute the CRC + uint16_t its_crc = profile_05::compute_crc(config_, _buffer); + bithelper::write_uint16_be(its_crc, &_buffer[config_.offset_]); + + // increment the Counter (new value will be used in the next invocation of E2E_P05Protect()), + increment_counter(_instance); + } +} + +void +protector::write_counter(e2e_buffer &_buffer, uint8_t _data, size_t _index) { + + _buffer[config_.offset_ + _index] = _data; +} + +uint8_t +protector::get_counter(instance_t _instance) const { + + uint8_t its_counter(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + its_counter = find_counter->second; + + return its_counter; +} + +void +protector::increment_counter(instance_t _instance) { + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + find_counter->second++; + else + counter_[_instance] = 1; +} + +} // namespace profile05 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp new file mode 100644 index 00000000000..eab7439e796 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/checker.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "../../../../include/e2e/profile/profile07/checker.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +// [SWS_E2E_00495] +void profile_07_checker::check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + std::lock_guard<std::mutex> lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + /** @req [SWS_E2E_00496] */ + if (verify_input(_buffer)) { + /** @req [SWS_E2E_00497] */ + uint32_t its_received_length; + if (read_32(_buffer, its_received_length, PROFILE_07_SIZE_OFFSET)) { + /** @req [SWS_E2E_00498] */ + uint32_t its_received_counter; + if (read_32(_buffer, its_received_counter, PROFILE_07_COUNTER_OFFSET)) { + /** @req [SWS_E2E_00499] */ + uint32_t its_received_data_id; + if (read_32(_buffer, its_received_data_id, PROFILE_07_DATAID_OFFSET)) { + /** @req [SWS_E2E_00500] */ + uint64_t its_received_crc; + if (read_64(_buffer, its_received_crc, PROFILE_07_CRC_OFFSET)) { + uint64_t its_crc = profile_07::compute_crc(config_, _buffer); + /** @req [SWS_E2E_00501] */ + if (its_received_crc != its_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_ERROR << std::hex << "E2E P07 protection: CRC32 does not match: calculated CRC: " + << its_crc << " received CRC: " << its_received_crc; + } else { + if (its_received_data_id == config_.data_id_ + && static_cast<size_t>(its_received_length) == _buffer.size() + && verify_counter(_instance, its_received_counter)) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } + } + } + } + } + } + } +} + +bool +profile_07_checker::verify_input(const e2e_buffer &_buffer) const { + + auto its_length = _buffer.size(); + return (its_length >= config_.min_data_length_ + && its_length <= config_.max_data_length_); +} + +bool +profile_07_checker::verify_counter(instance_t _instance, uint32_t _received_counter) { + + uint32_t its_delta(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) { + uint32_t its_counter = find_counter->second; + if (its_counter < _received_counter) + its_delta = uint32_t(_received_counter - its_counter); + else + its_delta = uint32_t(uint32_t(0xffffffff) - its_counter + _received_counter); + } else { + counter_[_instance] = _received_counter; + } + + return (its_delta <= config_.max_delta_counter_); +} + +// Read uint32_t as big-endian +bool +profile_07_checker::read_32(const e2e_buffer &_buffer, + uint32_t &_data, size_t _index) const { + + _data = bithelper::read_uint32_be(&_buffer[config_.offset_ + _index]); + return true; +} + +// Read uint64_t as big-endian +bool +profile_07_checker::read_64(const e2e_buffer &_buffer, + uint64_t &_data, size_t _index) const { + + _data = bithelper::read_uint64_be(&_buffer[config_.offset_ + _index]); + return true; +} + + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/profile_07.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/profile_07.cpp new file mode 100644 index 00000000000..6c9b7ce1aeb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/profile_07.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/crc/crc.hpp" +#include "../../../../include/e2e/profile/profile07/profile_07.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +uint64_t profile_07::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + + buffer_view its_before(_buffer, _config.offset_); + uint64_t computed_crc = e2e_crc::calculate_profile_07(its_before); + + if (_config.offset_ + 8 < _buffer.size()) { + buffer_view its_after(_buffer, _config.offset_ + 8, _buffer.size()); + computed_crc = e2e_crc::calculate_profile_07(its_after, computed_crc); + } + + return computed_crc; +} + +} // namespace profile07 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/protector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/protector.cpp new file mode 100644 index 00000000000..b470245ac86 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile07/protector.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile07/protector.hpp" +#include "../../../../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile07 { + +/** @req [SWS_E2E_00486] */ +void +protector::protect(e2e_buffer &_buffer, instance_t _instance) { + std::lock_guard<std::mutex> lock(protect_mutex_); + + /** @req: [SWS_E2E_00487] */ + if (verify_inputs(_buffer)) { + + /** @req [SWS_E2E_00489] */ + bithelper::write_uint32_be(static_cast<uint16_t>(_buffer.size()), &_buffer[config_.offset_ + PROFILE_07_SIZE_OFFSET]); + + /** @req [SWS_E2E_00490] */ + bithelper::write_uint32_be(get_counter(_instance), &_buffer[config_.offset_ + PROFILE_07_COUNTER_OFFSET]); + + /** @req [SWS_E2E_00491] */ + bithelper::write_uint32_be(config_.data_id_, &_buffer[config_.offset_ + PROFILE_07_DATAID_OFFSET]); + + /** @req [SWS_E2E_00492] */ + uint64_t its_crc = profile_07::compute_crc(config_, _buffer); + + /** @req [SWS_E2E_00493] */ + bithelper::write_uint64_be(its_crc, &_buffer[config_.offset_ + PROFILE_07_CRC_OFFSET]); + + /** @req [SWS_E2E_00494] */ + increment_counter(_instance); + } +} + +bool +protector::verify_inputs(e2e_buffer &_buffer) { + + return (_buffer.size() >= config_.min_data_length_ + && _buffer.size() <= config_.max_data_length_); +} + +uint32_t +protector::get_counter(instance_t _instance) const { + + uint32_t its_counter(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + its_counter = find_counter->second; + + return its_counter; +} + +void +protector::increment_counter(instance_t _instance) { + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + find_counter->second++; + else + counter_[_instance] = 1; +} + +} // namespace profile07 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp new file mode 100644 index 00000000000..bce5af95f12 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <algorithm> + +#include <vsomeip/internal/logger.hpp> +#include "../../../../include/e2e/profile/profile_custom/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +void profile_custom_checker::check(const e2e_buffer &_buffer, + instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + if (profile_custom::is_buffer_length_valid(config_, _buffer)) { + uint32_t received_crc(0); + uint32_t calculated_crc(0); + + received_crc = read_crc(_buffer); + calculated_crc = profile_custom::compute_crc(config_, _buffer); + if (received_crc == calculated_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } else { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_INFO << std::hex << "E2E protection: CRC32 does not match: calculated CRC: " + << (uint32_t) calculated_crc << " received CRC: " << (uint32_t) received_crc; + } + } +} + +uint32_t profile_custom_checker::read_crc(const e2e_buffer &_buffer) const { + return (static_cast<uint32_t>(_buffer[config_.crc_offset_ ]) << 24U) | + (static_cast<uint32_t>(_buffer[config_.crc_offset_ + 1U]) << 16U) | + (static_cast<uint32_t>(_buffer[config_.crc_offset_ + 2U]) << 8U) | + static_cast<uint32_t>(_buffer[config_.crc_offset_ + 3U]); +} + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/profile_custom.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/profile_custom.cpp new file mode 100644 index 00000000000..4e2936ede83 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/profile_custom.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/crc/crc.hpp" +#include "../../../../include/e2e/profile/profile_custom/profile_custom.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +uint32_t profile_custom::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + uint32_t computed_crc = e2e_crc::calculate_profile_custom(buffer_view(_buffer, static_cast<size_t>(_config.crc_offset_ + 4), _buffer.size())); + return computed_crc; +} + +bool profile_custom::is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer) { + return ((_config.crc_offset_ + 4U) <=_buffer.size()); +} + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp new file mode 100644 index 00000000000..1fd0ccb7145 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/e2e/profile/profile_custom/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile_custom { + +void protector::protect(e2e_buffer &_buffer, instance_t _instance) { + + (void)_instance; + + std::lock_guard<std::mutex> lock(protect_mutex_); + + if (profile_custom::is_buffer_length_valid(config_, _buffer)) { + // compute the CRC over DataID and Data + uint32_t computed_crc = profile_custom::compute_crc(config_, _buffer); + // write CRC in Data + write_crc(_buffer, computed_crc); + } +} + +void protector::write_crc(e2e_buffer &_buffer, uint32_t _computed_crc) { + _buffer[config_.crc_offset_] = static_cast<uint8_t>(_computed_crc >> 24U); + _buffer[config_.crc_offset_ + 1U] = static_cast<uint8_t>(_computed_crc >> 16U); + _buffer[config_.crc_offset_ + 2U] = static_cast<uint8_t>(_computed_crc >> 8U); + _buffer[config_.crc_offset_ + 3U] = static_cast<uint8_t>(_computed_crc); +} + +} // namespace profile_custom +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2exf/config.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2exf/config.cpp new file mode 100644 index 00000000000..6f124d3db2a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/e2e_protection/src/e2exf/config.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <ostream> +#include "../../../e2e_protection/include/e2exf/config.hpp" + +namespace vsomeip_v3 { + +std::ostream &operator<<(std::ostream &_os, const e2exf::data_identifier_t &_data_identifier) { + _os << _data_identifier.first << _data_identifier.second; + return _os; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/buffer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/buffer.hpp new file mode 100644 index 00000000000..32429be60c3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/buffer.hpp @@ -0,0 +1,68 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_BUFFER_HPP_ +#define VSOMEIP_V3_BUFFER_HPP_ + +#include <array> +#include <chrono> +#include <memory> +#include <set> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/primitive_types.hpp> + +#if defined(_WIN32) && !defined(_MSVC_LANG) + #define DEFAULT_NANOSECONDS_MAX 1000000000 +#else + #define DEFAULT_NANOSECONDS_MAX std::chrono::nanoseconds::max() +#endif + +namespace vsomeip_v3 { + +typedef std::vector<byte_t> message_buffer_t; +typedef std::shared_ptr<message_buffer_t> message_buffer_ptr_t; + +#if 0 +struct timing { + timing() : debouncing_(0), maximum_retention_(DEFAULT_NANOSECONDS_MAX) {}; + + std::chrono::nanoseconds debouncing_; + std::chrono::nanoseconds maximum_retention_; +}; +#endif + +struct train { + train() + : buffer_(std::make_shared<message_buffer_t>()), + minimal_debounce_time_(DEFAULT_NANOSECONDS_MAX), + minimal_max_retention_time_(DEFAULT_NANOSECONDS_MAX), + departure_(std::chrono::steady_clock::now() + std::chrono::hours(6)) { + }; + + void reset() { + buffer_ = std::make_shared<message_buffer_t>(); + passengers_.clear(); + minimal_debounce_time_ = DEFAULT_NANOSECONDS_MAX; + minimal_max_retention_time_ = DEFAULT_NANOSECONDS_MAX; + departure_ = std::chrono::steady_clock::now() + std::chrono::hours(6); + } + + message_buffer_ptr_t buffer_; + std::set<std::pair<service_t, method_t> > passengers_; + + std::chrono::nanoseconds minimal_debounce_time_; + std::chrono::nanoseconds minimal_max_retention_time_; + + std::chrono::steady_clock::time_point departure_; +}; + + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_BUFFER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint.hpp new file mode 100644 index 00000000000..372a1225843 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CLIENT_ENDPOINT_HPP_ +#define VSOMEIP_V3_CLIENT_ENDPOINT_HPP_ + +#include "endpoint.hpp" + +namespace vsomeip_v3 { + +class client_endpoint : public virtual endpoint { +public: + virtual ~client_endpoint() {} + + virtual bool get_remote_address(boost::asio::ip::address &_address) const = 0; + virtual std::uint16_t get_remote_port() const = 0; +}; + +} // namespace vsomeip + + +#endif // VSOMEIP_V3_CLIENT_ENDPOINT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint_impl.hpp new file mode 100644 index 00000000000..42cc53a362f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/client_endpoint_impl.hpp @@ -0,0 +1,168 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CLIENT_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_CLIENT_ENDPOINT_IMPL_HPP_ + +#include <atomic> +#include <condition_variable> +#include <deque> +#include <mutex> +#include <vector> +#include <chrono> +#include <thread> + +#include <boost/array.hpp> +#include <boost/asio/strand.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/utility.hpp> +#include <vsomeip/constants.hpp> + +#include "buffer.hpp" +#include "endpoint_impl.hpp" +#include "client_endpoint.hpp" +#include "tp.hpp" + +namespace vsomeip_v3 { + +class endpoint; +class endpoint_host; + +template<typename Protocol> +class client_endpoint_impl: public endpoint_impl<Protocol>, public client_endpoint, + public std::enable_shared_from_this<client_endpoint_impl<Protocol> > { +public: + typedef typename Protocol::endpoint endpoint_type; + typedef typename Protocol::socket socket_type; + + client_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~client_endpoint_impl(); + + bool send(const uint8_t *_data, uint32_t _size); + bool send(const std::vector<byte_t>& _cmd_header, const byte_t *_data, + uint32_t _size); + bool send_to(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool flush(); + + void prepare_stop(const endpoint::prepare_stop_handler_t &_handler, service_t _service); + virtual void stop(); + virtual void restart(bool _force = false) = 0; + + bool is_client() const; + + bool is_established() const; + bool is_established_or_connected() const; + void set_established(bool _established); + void set_connected(bool _connected); + virtual bool get_remote_address(boost::asio::ip::address &_address) const; + virtual std::uint16_t get_remote_port() const; + + std::uint16_t get_local_port() const; + void set_local_port(uint16_t _port); + virtual bool is_reliable() const = 0; + + size_t get_queue_size() const; + +public: + void cancel_and_connect_cbk(boost::system::error_code const &_error); + void connect_cbk(boost::system::error_code const &_error); + void wait_connect_cbk(boost::system::error_code const &_error); + void wait_connecting_cbk(boost::system::error_code const &_error); + virtual void send_cbk(boost::system::error_code const &_error, + std::size_t _bytes, const message_buffer_ptr_t& _sent_msg); + void flush_cbk(boost::system::error_code const &_error); + +public: + virtual void connect() = 0; + virtual void receive() = 0; + virtual void print_status() = 0; + +protected: + enum class cei_state_e : std::uint8_t { + CLOSED, + CONNECTING, + CONNECTED, + ESTABLISHED + }; + std::pair<message_buffer_ptr_t, uint32_t> get_front(); + virtual void send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry) = 0; + virtual void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const = 0; + void shutdown_and_close_socket(bool _recreate_socket); + void shutdown_and_close_socket_unlocked(bool _recreate_socket); + void start_connect_timer(); + void start_connecting_timer(); + typename endpoint_impl<Protocol>::cms_ret_e check_message_size( + const std::uint8_t * const _data, std::uint32_t _size); + bool check_queue_limit(const uint8_t *_data, std::uint32_t _size) const; + void queue_train(const std::shared_ptr<train> &_train); + void update_last_departure(); + +protected: + mutable std::mutex socket_mutex_; + std::unique_ptr<socket_type> socket_; + const endpoint_type remote_; + + boost::asio::steady_timer flush_timer_; + + std::mutex connect_timer_mutex_; + boost::asio::steady_timer connect_timer_; + std::atomic<uint32_t> connect_timeout_; + std::atomic<cei_state_e> state_; + std::atomic<std::uint32_t> reconnect_counter_; + + std::mutex connecting_timer_mutex_; + boost::asio::steady_timer connecting_timer_; + std::atomic<uint32_t> connecting_timeout_; + + + // send data + std::shared_ptr<train> train_; + std::map<std::chrono::steady_clock::time_point, + std::deque<std::shared_ptr<train> > > dispatched_trains_; + boost::asio::steady_timer dispatch_timer_; + std::chrono::steady_clock::time_point last_departure_; + std::atomic<bool> has_last_departure_; + + std::deque<std::pair<message_buffer_ptr_t, uint32_t> > queue_; + std::size_t queue_size_; + + mutable std::recursive_mutex mutex_; + + std::atomic<bool> was_not_connected_; + + bool is_sending_; + + boost::asio::io_context::strand strand_; + +private: + virtual void set_local_port() = 0; + virtual std::string get_remote_information() const = 0; + virtual bool tp_segmentation_enabled(service_t _service, + instance_t _instance, + method_t _method) const; + virtual std::uint32_t get_max_allowed_reconnects() const = 0; + virtual void max_allowed_reconnects_reached() = 0; + void send_segments(const tp::tp_split_messages_t &_segments, + std::uint32_t _separation_time); + + void schedule_train(); + + void start_dispatch_timer(const std::chrono::steady_clock::time_point &_now); + void cancel_dispatch_timer(); +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CLIENT_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/credentials.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/credentials.hpp new file mode 100644 index 00000000000..bb4ee448f2a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/credentials.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINTS_INCLUDE_CREDENTIALS_HPP_ +#define VSOMEIP_V3_ENDPOINTS_INCLUDE_CREDENTIALS_HPP_ + +#include <tuple> + +#include <boost/optional.hpp> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +class credentials { +public: + static void activate_credentials(const int _fd); + + static void deactivate_credentials(const int _fd); + + using received_t = std::tuple<client_t, uid_t, gid_t, std::string>; + static boost::optional<received_t> receive_credentials(const int _fd); + + static void send_credentials(const int _fd, client_t _client, std::string _client_host); +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINTS_INCLUDE_CREDENTIALS_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint.hpp new file mode 100644 index 00000000000..550fa28e410 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_HPP_ +#define VSOMEIP_V3_ENDPOINT_HPP_ + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/constants.hpp> + +#include <vector> + +namespace vsomeip_v3 { + +class endpoint_definition; + +class endpoint { +public: + typedef std::function<void()> error_handler_t; + typedef std::function<void(const std::shared_ptr<endpoint> &)> prepare_stop_handler_t; + + virtual ~endpoint() = default; + + virtual void start() = 0; + virtual void restart(bool _force = false) = 0; + virtual void stop() = 0; + + virtual void prepare_stop(const prepare_stop_handler_t &_handler, + service_t _service = ANY_SERVICE) = 0; + + virtual bool is_established() const = 0; + virtual bool is_established_or_connected() const = 0; + + virtual bool send(const byte_t *_data, uint32_t _size) = 0; + virtual bool send_to(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) = 0; + virtual bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) = 0; + virtual void enable_magic_cookies() = 0; + virtual void receive() = 0; + + virtual void add_default_target(service_t _service, + const std::string &_address, uint16_t _port) = 0; + virtual void remove_default_target(service_t _service) = 0; + virtual void remove_stop_handler(service_t _service) = 0; + + virtual std::uint16_t get_local_port() const = 0; + virtual void set_local_port(uint16_t _port) = 0; + virtual bool is_reliable() const = 0; + virtual bool is_local() const = 0; + + virtual void register_error_handler(const error_handler_t &_error) = 0; + + virtual void print_status() = 0; + virtual size_t get_queue_size() const = 0; + + virtual void set_established(bool _established) = 0; + virtual void set_connected(bool _connected) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_definition.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_definition.hpp new file mode 100644 index 00000000000..2dca226eae0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_definition.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_DEFINITION_HPP_ +#define VSOMEIP_V3_ENDPOINT_DEFINITION_HPP_ + +#include <map> +#include <memory> +#include <atomic> +#include <mutex> + +#include <boost/asio/ip/address.hpp> +#include <vsomeip/primitive_types.hpp> + +#include <vsomeip/export.hpp> + +namespace vsomeip_v3 { + +class endpoint_definition { +public: + VSOMEIP_EXPORT static std::shared_ptr<endpoint_definition> get( + const boost::asio::ip::address &_address, + uint16_t _port, bool _is_reliable, service_t _service, instance_t _instance); + + VSOMEIP_EXPORT const boost::asio::ip::address &get_address() const; + + VSOMEIP_EXPORT uint16_t get_port() const; + + VSOMEIP_EXPORT uint16_t get_remote_port() const; + VSOMEIP_EXPORT void set_remote_port(uint16_t _port); + + VSOMEIP_EXPORT bool is_reliable() const; + + VSOMEIP_EXPORT endpoint_definition( + const boost::asio::ip::address &_address, + uint16_t _port, bool _is_reliable); +private: + boost::asio::ip::address address_; + uint16_t port_; + std::atomic<uint16_t> remote_port_; + bool is_reliable_; + + static std::mutex definitions_mutex_; + static std::map< + std::tuple<service_t, instance_t, boost::asio::ip::address, uint16_t, bool>, + std::shared_ptr<endpoint_definition> > definitions_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_DEFINITION_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_host.hpp new file mode 100644 index 00000000000..e5ca6d13139 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_host.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_HOST_HPP_ +#define VSOMEIP_V3_ENDPOINT_HOST_HPP_ + +#include <memory> + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif + +namespace vsomeip_v3 { + +class configuration; +class endpoint; + +struct multicast_option_t { + std::shared_ptr<endpoint> endpoint_; + bool is_join_; + boost::asio::ip::address address_; +}; + +class endpoint_host { +public: + virtual ~endpoint_host() = default; + + virtual void on_connect(std::shared_ptr<endpoint> _endpoint) = 0; + virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint) = 0; + virtual bool on_bind_error(std::shared_ptr<endpoint> _endpoint, + const boost::asio::ip::address &_remote_address, + uint16_t _remote_port) = 0; + virtual void on_error(const byte_t *_data, length_t _length, + endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) = 0; + virtual void release_port(uint16_t _port, bool _reliable) = 0; + virtual client_t get_client() const = 0; + virtual std::string get_client_host() const = 0; + virtual instance_t find_instance(service_t _service, + endpoint * const _endpoint) const = 0; + virtual void add_multicast_option(const multicast_option_t &_option) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_HOST_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_impl.hpp new file mode 100644 index 00000000000..598174dd0fc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_impl.hpp @@ -0,0 +1,103 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_ENDPOINT_IMPL_HPP_ + +#include <map> +#include <memory> +#include <mutex> +#include <atomic> + +#include <boost/asio/steady_timer.hpp> + +#include "buffer.hpp" +#include "endpoint.hpp" +#include "../../configuration/include/configuration.hpp" + +namespace vsomeip_v3 { + +class endpoint_host; +class routing_host; + +template<typename Protocol> +class endpoint_impl: public virtual endpoint { +public: + typedef typename Protocol::endpoint endpoint_type; + + endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, boost::asio::io_context& _io, + const std::shared_ptr<configuration>& _configuration); + endpoint_impl(endpoint_impl<Protocol> const&) = delete; + endpoint_impl(endpoint_impl<Protocol> const&&) = delete; + virtual ~endpoint_impl() = default; + + void enable_magic_cookies(); + + void add_default_target(service_t, const std::string &, uint16_t); + void remove_default_target(service_t); + void remove_stop_handler(service_t); + + virtual std::uint16_t get_local_port() const = 0; + virtual void set_local_port(uint16_t _port) = 0; + virtual bool is_reliable() const = 0; + + void register_error_handler(const error_handler_t &_error_handler); + virtual void print_status() = 0; + + virtual size_t get_queue_size() const = 0; + +public: + // required + virtual bool is_client() const = 0; + virtual void receive() = 0; + virtual void restart(bool _force) = 0; + +protected: + uint32_t find_magic_cookie(byte_t *_buffer, size_t _size); + instance_t get_instance(service_t _service); + +protected: + enum class cms_ret_e : uint8_t { + MSG_TOO_BIG, + MSG_OK, + MSG_WAS_SPLIT + }; + + // Reference to service context + boost::asio::io_context &io_; + + // References to hosts + std::weak_ptr<endpoint_host> endpoint_host_; + std::weak_ptr<routing_host> routing_host_; + + bool is_supporting_magic_cookies_; + std::atomic<bool> has_enabled_magic_cookies_; + + // Filter configuration + std::map<service_t, uint8_t> opened_; + + std::uint32_t max_message_size_; + + std::atomic<uint32_t> use_count_; + + std::atomic<bool> sending_blocked_; + + std::mutex local_mutex_; + endpoint_type local_; + + error_handler_t error_handler_; + std::mutex error_handler_mutex_; + + configuration::endpoint_queue_limit_t queue_limit_; + + std::shared_ptr<configuration> configuration_; + + bool is_supporting_someip_tp_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_base.hpp new file mode 100644 index 00000000000..295e25c137b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_base.hpp @@ -0,0 +1,101 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_MANAGER_BASE_HPP_ +#define VSOMEIP_V3_ENDPOINT_MANAGER_BASE_HPP_ + +#include <mutex> +#include <map> +#include <set> +#include <unordered_set> +#include <memory> + +#include <boost/asio/io_context.hpp> +#include <vsomeip/primitive_types.hpp> + +#include "endpoint.hpp" +#include "endpoint_host.hpp" + +namespace vsomeip_v3 { + +class routing_manager_base; +class configuration; +class routing_host; + +class endpoint_manager_base + : public std::enable_shared_from_this<endpoint_manager_base>, + public endpoint_host { +public: + endpoint_manager_base(routing_manager_base* const _rm, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~endpoint_manager_base() = default; + + std::shared_ptr<endpoint> create_local(client_t _client); + void remove_local(client_t _client); + + std::shared_ptr<endpoint> find_or_create_local(client_t _client); + std::shared_ptr<endpoint> find_local(client_t _client); + std::shared_ptr<endpoint> find_local(service_t _service, instance_t _instance); + + std::unordered_set<client_t> get_connected_clients() const; + + std::shared_ptr<endpoint> create_local_server( + const std::shared_ptr<routing_host> &_routing_host); + + // endpoint_host interface + virtual void on_connect(std::shared_ptr<endpoint> _endpoint); + virtual void on_disconnect(std::shared_ptr<endpoint> _endpoint); + virtual bool on_bind_error(std::shared_ptr<endpoint> _endpoint, + const boost::asio::ip::address &_remote_address, + uint16_t _remote_port); + virtual void on_error(const byte_t *_data, length_t _length, + endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + virtual void release_port(uint16_t _port, bool _reliable); + client_t get_client() const; + std::string get_client_host() const; + instance_t find_instance(service_t _service, + endpoint* const _endpoint) const; + + // Statistics + void log_client_states() const; + + // Multicast options + void add_multicast_option(const multicast_option_t &_option); + + virtual void suspend(void); + virtual void resume(void); + +protected: + std::map<client_t, std::shared_ptr<endpoint>> get_local_endpoints() const; + +private: + std::shared_ptr<endpoint> create_local_unlocked(client_t _client); + std::shared_ptr<endpoint> find_local_unlocked(client_t _client); + + bool get_local_server_port(port_t &_port, const std::set<port_t> &_used_ports) const; + +protected: + routing_manager_base* const rm_; + boost::asio::io_context &io_; + std::shared_ptr<configuration> configuration_; + + bool is_local_routing_; + port_t local_port_; // local (client) port when connecting to other + // vsomeip application via TCP + +private: + mutable std::mutex local_endpoint_mutex_; + std::map<client_t, std::shared_ptr<endpoint> > local_endpoints_; + + mutable std::mutex create_local_server_endpoint_mutex_; + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_MANAGER_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_impl.hpp new file mode 100644 index 00000000000..403a709b1e3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/endpoint_manager_impl.hpp @@ -0,0 +1,177 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENDPOINT_MANAGER_IMPL_HPP_ +#define VSOMEIP_V3_ENDPOINT_MANAGER_IMPL_HPP_ + +#include <condition_variable> +#include <queue> +#include <thread> + +#include "../include/endpoint_manager_base.hpp" + +namespace vsomeip_v3 { + +class routing_host; + +class endpoint_manager_impl : public endpoint_manager_base { +public: + endpoint_manager_impl(routing_manager_base* const _rm, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + ~endpoint_manager_impl(); + + std::shared_ptr<endpoint> find_or_create_remote_client(service_t _service, + instance_t _instance, + bool _reliable); + + void find_or_create_remote_client(service_t _service, instance_t _instance); + void is_remote_service_known( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, + const boost::asio::ip::address &_reliable_address, + uint16_t _reliable_port, bool* _reliable_known, + const boost::asio::ip::address &_unreliable_address, + uint16_t _unreliable_port, bool* _unreliable_known) const; + void add_remote_service_info( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint_definition>& _ep_definition); + void add_remote_service_info( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint_definition>& _ep_definition_reliable, + const std::shared_ptr<endpoint_definition>& _ep_definition_unreliable); + void clear_remote_service_info(service_t _service, instance_t _instance, + bool _reliable); + + std::shared_ptr<endpoint> create_server_endpoint(uint16_t _port, + bool _reliable, + bool _start); + + std::shared_ptr<endpoint> find_server_endpoint(uint16_t _port, + bool _reliable) const; + + std::shared_ptr<endpoint> find_or_create_server_endpoint( + uint16_t _port, bool _reliable, bool _start, service_t _service, + instance_t _instance, bool &_is_found, bool _is_multicast = false); + bool remove_server_endpoint(uint16_t _port, bool _reliable); + + + void clear_client_endpoints(service_t _service, instance_t _instance, + bool _reliable); + void find_or_create_multicast_endpoint( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port); + void clear_multicast_endpoints(service_t _service, instance_t _instance); + + bool supports_selective(service_t _service, instance_t _instance) const; + + void print_status() const; + + bool create_routing_root( + std::shared_ptr<endpoint> &_root, + bool &_is_socket_activated, + const std::shared_ptr<routing_host> &_host); + + instance_t find_instance(service_t _service, + endpoint* const _endpoint) const; + instance_t find_instance_multicast(service_t _service, + const boost::asio::ip::address &_sender) const; + + bool remove_instance(service_t _service, endpoint* const _endpoint); + bool remove_instance_multicast(service_t _service, instance_t _instance); + + + // endpoint_host interface + void on_connect(std::shared_ptr<endpoint> _endpoint); + void on_disconnect(std::shared_ptr<endpoint> _endpoint); + bool on_bind_error(std::shared_ptr<endpoint> _endpoint, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + void on_error(const byte_t *_data, length_t _length, + endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + + void get_used_client_ports( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + std::map<bool, std::set<port_t> > &_used_ports); + void request_used_client_port( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + bool _reliable, port_t _local_port); + void release_used_client_port( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + bool _reliable, port_t _local_port); + + // Statistics + void log_client_states() const; + void log_server_states() const; + + // add join/leave options + void add_multicast_option(const multicast_option_t &_option); + + void suspend(void); + void resume(void); + +private: + std::shared_ptr<endpoint> find_remote_client(service_t _service, + instance_t _instance, + bool _reliable); + std::shared_ptr<endpoint> create_remote_client(service_t _service, + instance_t _instance, + bool _reliable); + std::shared_ptr<endpoint> create_client_endpoint( + const boost::asio::ip::address &_address, uint16_t _local_port, + uint16_t _remote_port, bool _reliable); + + // process join/leave options + void process_multicast_options(); + + bool is_used_endpoint(endpoint* const _endpoint) const; + +private: + mutable std::recursive_mutex endpoint_mutex_; + // Client endpoints for remote services + std::map<service_t, std::map<instance_t, + std::map<bool, std::shared_ptr<endpoint_definition>>>> remote_service_info_; + + typedef std::map<service_t, std::map<instance_t, + std::map<bool, std::shared_ptr<endpoint>>>> remote_services_t; + remote_services_t remote_services_; + + using client_endpoints_t = + std::map<boost::asio::ip::address, + std::map<uint16_t, + std::map<bool, std::map<partition_id_t, std::shared_ptr<endpoint>>>>>; + client_endpoints_t client_endpoints_; + + std::map<service_t, std::map<endpoint *, instance_t> > service_instances_; + std::map<service_t, std::map<boost::asio::ip::address, instance_t> > service_instances_multicast_; + + std::map<boost::asio::ip::address, + std::map<port_t, + std::map<bool, std::set<port_t> > + > + > used_client_ports_; + std::mutex used_client_ports_mutex_; + + // Server endpoints for local services + using server_endpoints_t = std::map<uint16_t, std::map<bool, std::shared_ptr<endpoint>>>; + server_endpoints_t server_endpoints_; + + // Multicast endpoint info (notifications) + std::map<service_t, std::map<instance_t, std::shared_ptr<endpoint_definition>>> multicast_info_; + + // Socket option processing (join, leave) + std::mutex options_mutex_; + bool is_processing_options_; + std::condition_variable options_condition_; + std::queue<multicast_option_t> options_queue_; + std::thread options_thread_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENDPOINT_MANAGER_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp new file mode 100644 index 00000000000..b911eb0cd19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp @@ -0,0 +1,141 @@ +// Copyright (C) 2020-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ +#define VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + +#include <boost/asio/local/stream_protocol.hpp> +#include <memory> + +namespace vsomeip_v3 { +namespace local_endpoint_receive_op { + +typedef boost::asio::local::stream_protocol::socket socket_type_t; +typedef std::function< + void (boost::system::error_code const &_error, size_t _size, + const std::uint32_t &, const std::uint32_t &)> receive_handler_t; + +struct storage : + public std::enable_shared_from_this<storage> +{ + socket_type_t &socket_; + receive_handler_t handler_; + byte_t *buffer_ = nullptr; + size_t length_; + uid_t uid_; + gid_t gid_; + size_t bytes_; + + storage( + socket_type_t &_socket, + receive_handler_t _handler, + byte_t *_buffer, + size_t _length, + uid_t _uid, + gid_t _gid, + size_t _bytes + ) : socket_(_socket), + handler_(_handler), + buffer_(_buffer), + length_(_length), + uid_(_uid), + gid_(_gid), + bytes_(_bytes) + {} +}; + +inline +std::function<void(boost::system::error_code _error)> +receive_cb (std::shared_ptr<storage> _data) { + return [_data](boost::system::error_code _error) { + if (!_error) { + if (!_data->socket_.native_non_blocking()) + _data->socket_.native_non_blocking(true, _error); + #if defined(__linux__) + for (;;) { + ssize_t its_result; + int its_flags(0); + + // Set buffer + struct iovec its_vec[1]; + its_vec[0].iov_base = _data->buffer_; + its_vec[0].iov_len = _data->length_; + + union { + struct cmsghdr cmh; + char control[CMSG_SPACE(sizeof(struct ucred))]; + } control_un; + + // Set 'control_un' to describe ancillary data that we want to receive + control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + control_un.cmh.cmsg_level = SOL_SOCKET; + control_un.cmh.cmsg_type = SCM_CREDENTIALS; + + // Build header with all informations to call ::recvmsg + auto its_header = msghdr(); + its_header.msg_iov = its_vec; + its_header.msg_iovlen = 1; + its_header.msg_control = control_un.control; + its_header.msg_controllen = sizeof(control_un.control); + + // Call recvmsg and handle its result + errno = 0; + its_result = ::recvmsg(_data->socket_.native_handle(), &its_header, its_flags); + _error = boost::system::error_code(its_result < 0 ? errno : 0, + boost::asio::error::get_system_category()); + _data->bytes_ += _error ? 0 : static_cast<size_t>(its_result); + + if (_error == boost::asio::error::interrupted) + continue; + + if (_error == boost::asio::error::would_block + || _error == boost::asio::error::try_again) { + _data->socket_.async_wait(socket_type_t::wait_read, receive_cb(_data)); + return; + } + + if (_error) + break; + + if (_data->bytes_ == 0) + _error = boost::asio::error::eof; + + // Extract credentials (UID/GID) + struct ucred *its_credentials; + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&its_header); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&its_header, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SCM_CREDENTIALS + && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + its_credentials = (struct ucred *) CMSG_DATA(cmsg); + if (its_credentials) { + _data->uid_ = its_credentials->uid; + _data->gid_ = its_credentials->gid; + break; + } + } + } + + break; + } + #endif + } + + // Call the handler + _data->handler_(_error, _data->bytes_, _data->uid_, _data->gid_); + }; +} + +} // namespace local_endpoint_receive_op +} // namespace vsomeip + +#endif // __linux__ || ANDROID + +#endif // VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_client_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_client_endpoint_impl.hpp new file mode 100644 index 00000000000..413e88a177a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_client_endpoint_impl.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOCAL_TCP_CLIENT_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_LOCAL_TCP_CLIENT_ENDPOINT_IMPL_HPP_ + +#include <boost/asio/ip/tcp.hpp> + +#include <vsomeip/defines.hpp> + +#include "client_endpoint_impl.hpp" + +namespace vsomeip_v3 { + +typedef client_endpoint_impl< + boost::asio::ip::tcp + > local_tcp_client_endpoint_base_impl; + +class local_tcp_client_endpoint_impl: public local_tcp_client_endpoint_base_impl { +public: + local_tcp_client_endpoint_impl(const std::shared_ptr<endpoint_host> &_endpoint_host, + const std::shared_ptr<routing_host> &_routing_host, + const endpoint_type &_local, + const endpoint_type &_remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration> &_configuration); + virtual ~local_tcp_client_endpoint_impl() = default; + + void start(); + void stop(); + + bool is_local() const; + + std::uint16_t get_local_port() const; + + void restart(bool _force); + void print_status(); + + bool is_reliable() const; + + // this overrides client_endpoint_impl::send to disable the pull method + // for local communication + bool send(const uint8_t *_data, uint32_t _size); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; +private: + void send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry); + + void send_magic_cookie(); + + void connect(); + void receive(); + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes); + void set_local_port(); + std::string get_remote_information() const; + bool check_packetizer_space(std::uint32_t _size); + std::uint32_t get_max_allowed_reconnects() const; + void max_allowed_reconnects_reached(); + + message_buffer_t recv_buffer_; + + // send data + message_buffer_ptr_t send_data_buffer_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_LOCAL_TCP_CLIENT_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_server_endpoint_impl.hpp new file mode 100644 index 00000000000..1008c1a7f0c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_tcp_server_endpoint_impl.hpp @@ -0,0 +1,172 @@ +// Copyright (C) 2014-2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOCAL_TCP_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_LOCAL_TCP_SERVER_ENDPOINT_IMPL_HPP_ + +#include <map> +#include <thread> +#include <condition_variable> +#include <memory> + +#include <boost/asio/ip/tcp.hpp> + +#include <vsomeip/defines.hpp> + +#include "buffer.hpp" +#include "server_endpoint_impl.hpp" + +namespace vsomeip_v3 { + +typedef server_endpoint_impl< + boost::asio::ip::tcp + > local_tcp_server_endpoint_base_impl; + +class local_tcp_server_endpoint_impl + : public local_tcp_server_endpoint_base_impl { + +public: + local_tcp_server_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint); + virtual ~local_tcp_server_endpoint_impl() = default; + + void init(const endpoint_type& _local, boost::system::error_code& _error); + void deinit(); + + void start(); + void stop(); + + void receive(); + + // this overrides server_endpoint_impl::send to disable the nPDU feature + // for local communication + bool send(const uint8_t *_data, uint32_t _size); + bool send_to(const std::shared_ptr<endpoint_definition>, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_queued(const target_data_iterator_type _queue_iterator); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + + bool get_default_target(service_t, endpoint_type &) const; + + bool is_local() const; + + void accept_client_func(); + void print_status(); + + bool is_reliable() const; + std::uint16_t get_local_port() const; + void set_local_port(std::uint16_t _port); + + client_t assign_client(const byte_t *_data, uint32_t _size); + +private: + class connection: public std::enable_shared_from_this<connection> { + + public: + typedef std::shared_ptr<connection> ptr; + + static ptr create(const std::shared_ptr<local_tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io); + socket_type & get_socket(); + std::unique_lock<std::mutex> get_socket_lock(); + + void start(); + void stop(); + + + void send_queued(const message_buffer_ptr_t& _buffer); + + void set_bound_client(client_t _client); + client_t get_bound_client() const; + + void set_bound_client_host(const std::string &_bound_client_host); + std::string get_bound_client_host() const; + + std::size_t get_recv_buffer_capacity() const; + + private: + connection(const std::shared_ptr<local_tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _initial_recv_buffer_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io); + + void send_cbk(const message_buffer_ptr_t _buffer, + boost::system::error_code const &_error, std::size_t _bytes); + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes); + void calculate_shrink_count(); + std::string get_path_local() const; + std::string get_path_remote() const; + void handle_recv_buffer_exception(const std::exception &_e); + void shutdown_and_close(); + void shutdown_and_close_unlocked(); + + std::mutex socket_mutex_; + local_tcp_server_endpoint_impl::socket_type socket_; + std::weak_ptr<local_tcp_server_endpoint_impl> server_; + + const std::uint32_t recv_buffer_size_initial_; + const std::uint32_t max_message_size_; + + message_buffer_t recv_buffer_; + size_t recv_buffer_size_; + std::uint32_t missing_capacity_; + std::uint32_t shrink_count_; + const std::uint32_t buffer_shrink_threshold_; + + client_t bound_client_; + std::string bound_client_host_; + + vsomeip_sec_client_t sec_client_; + + bool assigned_client_; + std::atomic<bool> is_stopped_; + }; + + std::mutex acceptor_mutex_; + boost::asio::ip::tcp::acceptor acceptor_; + + typedef std::map<client_t, connection::ptr> connections_t; + std::mutex connections_mutex_; + connections_t connections_; + + const std::uint32_t buffer_shrink_threshold_; + + port_t local_port_; + + const bool is_routing_endpoint_; + +private: + void init_unlocked(const endpoint_type& _local, boost::system::error_code& _error); + bool add_connection(const client_t &_client, + const std::shared_ptr<connection> &_connection); + void remove_connection(const client_t &_client); + void accept_cbk(const connection::ptr& _connection, + boost::system::error_code const &_error); + std::string get_remote_information( + const target_data_iterator_type _queue_iterator) const; + std::string get_remote_information( + const endpoint_type& _remote) const; + + bool check_packetizer_space(target_data_iterator_type _queue_iterator, + message_buffer_ptr_t* _packetizer, + std::uint32_t _size); + void send_client_identifier(const client_t &_client); +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_LOCAL_TCP_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_client_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_client_endpoint_impl.hpp new file mode 100644 index 00000000000..0c218c04045 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_client_endpoint_impl.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2014-2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOCAL_UDS_CLIENT_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_LOCAL_UDS_CLIENT_ENDPOINT_IMPL_HPP_ + +#include <boost/asio/local/stream_protocol.hpp> + +#include <vsomeip/defines.hpp> + +#include "client_endpoint_impl.hpp" + +namespace vsomeip_v3 { + +typedef client_endpoint_impl< + boost::asio::local::stream_protocol + > local_uds_client_endpoint_base_impl; + +class local_uds_client_endpoint_impl: public local_uds_client_endpoint_base_impl { +public: + local_uds_client_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~local_uds_client_endpoint_impl() = default; + + void start(); + void stop(); + + bool is_local() const; + + bool get_remote_address(boost::asio::ip::address &_address) const; + std::uint16_t get_remote_port() const; + + void restart(bool _force); + void print_status(); + + bool is_reliable() const; + + // this overrides client_endpoint_impl::send to disable the pull method + // for local communication + bool send(const uint8_t *_data, uint32_t _size); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; +private: + void send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry); + + void send_magic_cookie(); + + void connect(); + void receive(); + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes); + void set_local_port(); + std::string get_remote_information() const; + bool check_packetizer_space(std::uint32_t _size); + std::uint32_t get_max_allowed_reconnects() const; + void max_allowed_reconnects_reached(); + + message_buffer_t recv_buffer_; + + // send data + message_buffer_ptr_t send_data_buffer_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_LOCAL_UDS_CLIENT_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_server_endpoint_impl.hpp new file mode 100644 index 00000000000..a0d8bde1e44 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/local_uds_server_endpoint_impl.hpp @@ -0,0 +1,174 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOCAL_UDS_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_LOCAL_UDS_SERVER_ENDPOINT_IMPL_HPP_ + +#include <map> +#include <thread> +#include <condition_variable> +#include <memory> + +#include <boost/asio/local/stream_protocol.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "buffer.hpp" +#include "server_endpoint_impl.hpp" + +namespace vsomeip_v3 { + +typedef server_endpoint_impl<boost::asio::local::stream_protocol> + local_uds_server_endpoint_base_impl; + +class local_uds_server_endpoint_impl: public local_uds_server_endpoint_base_impl { +public: + local_uds_server_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint); + virtual ~local_uds_server_endpoint_impl() = default; + + void init(const endpoint_type& _local, boost::system::error_code& _error); + void init(const endpoint_type& _local, const int _socket, boost::system::error_code& _error); + void deinit(); + + void start(); + void stop(); + + void receive(); + + // this overrides server_endpoint_impl::send to disable the nPDU feature + // for local communication + bool send(const uint8_t *_data, uint32_t _size); + bool send_to(const std::shared_ptr<endpoint_definition>, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_queued(const target_data_iterator_type _queue_iterator); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + + bool get_default_target(service_t, endpoint_type &) const; + + bool is_local() const; + + void accept_client_func(); + void print_status(); + + bool is_reliable() const; + std::uint16_t get_local_port() const; + void set_local_port(std::uint16_t _port); + + client_t assign_client(const byte_t *_data, uint32_t _size); + +private: + class connection: public std::enable_shared_from_this<connection> { + + public: + typedef std::shared_ptr<connection> ptr; + + static ptr create(const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io); + socket_type & get_socket(); + std::unique_lock<std::mutex> get_socket_lock(); + + void start(); + void stop(); + + void send_queued(const message_buffer_ptr_t& _buffer); + + void set_bound_client(client_t _client); + client_t get_bound_client() const; + + void set_bound_client_host(const std::string &_bound_client_host); + std::string get_bound_client_host() const; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + void set_bound_sec_client(const vsomeip_sec_client_t &_sec_client); +#endif + + std::size_t get_recv_buffer_capacity() const; + + private: + connection(const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _initial_recv_buffer_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io); + + void send_cbk(const message_buffer_ptr_t _buffer, + boost::system::error_code const &_error, std::size_t _bytes); + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + , std::uint32_t const &_uid, std::uint32_t const &_gid +#endif + ); + void calculate_shrink_count(); + std::string get_path_local() const; + std::string get_path_remote() const; + void handle_recv_buffer_exception(const std::exception &_e); + void shutdown_and_close(); + void shutdown_and_close_unlocked(); + + std::mutex socket_mutex_; + local_uds_server_endpoint_impl::socket_type socket_; + std::weak_ptr<local_uds_server_endpoint_impl> server_; + + const std::uint32_t recv_buffer_size_initial_; + const std::uint32_t max_message_size_; + + message_buffer_t recv_buffer_; + size_t recv_buffer_size_; + std::uint32_t missing_capacity_; + std::uint32_t shrink_count_; + const std::uint32_t buffer_shrink_threshold_; + + client_t bound_client_; + std::string bound_client_host_; + + vsomeip_sec_client_t sec_client_; + + bool assigned_client_; + std::atomic<bool> is_stopped_; + }; + + std::mutex acceptor_mutex_; + boost::asio::local::stream_protocol::acceptor acceptor_; + typedef std::map<client_t, connection::ptr> connections_t; + std::mutex connections_mutex_; + connections_t connections_; + + const std::uint32_t buffer_shrink_threshold_; + + const bool is_routing_endpoint_; + +private: + void init_helper(const endpoint_type& _local, boost::system::error_code& _error); + bool add_connection(const client_t &_client, + const std::shared_ptr<connection> &_connection); + void remove_connection(const client_t &_client); + void accept_cbk(const connection::ptr& _connection, + boost::system::error_code const &_error); + std::string get_remote_information( + const target_data_iterator_type _queue_iterator) const; + std::string get_remote_information( + const endpoint_type& _remote) const; + + bool check_packetizer_space(target_data_iterator_type _queue_iterator, + message_buffer_ptr_t* _packetizer, + std::uint32_t _size); + void send_client_identifier(const client_t &_client); +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_LOCAL_UDS_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/netlink_connector.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/netlink_connector.hpp new file mode 100644 index 00000000000..deb11bf0610 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/netlink_connector.hpp @@ -0,0 +1,209 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_NETLINK_CONNECTOR_HPP_ +#define VSOMEIP_V3_NETLINK_CONNECTOR_HPP_ + +#if defined(__linux__) || defined(ANDROID) + +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include <map> +#include <mutex> + +#include <boost/asio/basic_raw_socket.hpp> +#include <boost/asio/ip/address.hpp> + +#include "../../endpoints/include/buffer.hpp" + +#ifdef ANDROID +# include "../../configuration/include/internal_android.hpp" +#else +# include "../../configuration/include/internal.hpp" +#endif + +namespace vsomeip_v3 { + +template <typename Protocol> +class nl_endpoint { +public: + /// The protocol type associated with the endpoint. + typedef Protocol protocol_type; + typedef boost::asio::detail::socket_addr_type data_type; + + /// Default constructor. + nl_endpoint() + { + sockaddr.nl_family = PF_NETLINK; + sockaddr.nl_groups = 0; + sockaddr.nl_pid = 0; // Let the kernel do the assignment + } + + /// Construct an endpoint using the specified path name. + nl_endpoint(int group) + { + sockaddr.nl_family = PF_NETLINK; + sockaddr.nl_groups = static_cast<unsigned int>(group); + sockaddr.nl_pid = 0; + } + + /// Copy constructor. + nl_endpoint(const nl_endpoint& other) + { + sockaddr = other.sockaddr; + } + + /// Assign from another endpoint. + nl_endpoint& operator=(const nl_endpoint& other) + { + sockaddr = other.sockaddr; + return *this; + } + + /// The protocol associated with the endpoint. + protocol_type protocol() const + { + return protocol_type(); + } + + /// Get the underlying endpoint in the native type. + data_type* data() + { + return reinterpret_cast<struct sockaddr*>(&sockaddr); + } + + /// Get the underlying endpoint in the native type. + const data_type* data() const + { + return reinterpret_cast<const struct sockaddr*>(&sockaddr); + } + + /// Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return sizeof(sockaddr); + } + + /// Set the underlying size of the endpoint in the native type. + void resize(std::size_t size) + { + (void)size; + /* nothing we can do here */ + } + + /// Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(sockaddr); + } + +private: + sockaddr_nl sockaddr; +}; + +class nl_protocol { +public: + nl_protocol() { + proto = 0; + } + nl_protocol(int proto) { + this->proto = proto; + } + /// Obtain an identifier for the type of the protocol. + int type() const + { + return SOCK_RAW; + } + /// Obtain an identifier for the protocol. + int protocol() const + { + return proto; + } + /// Obtain an identifier for the protocol family. + int family() const + { + return PF_NETLINK; + } + + typedef nl_endpoint<nl_protocol> endpoint; + typedef boost::asio::basic_raw_socket<nl_protocol> socket; + +private: + int proto; +}; + +typedef std::function< void ( + bool, // true = is interface, false = is route + std::string, // interface name + bool) // available? +> net_if_changed_handler_t; + +class netlink_connector : public std::enable_shared_from_this<netlink_connector> { +public: + netlink_connector(boost::asio::io_context &_io, const boost::asio::ip::address &_address, + const boost::asio::ip::address &_multicast_address, + bool _is_requiring_link = true): + net_if_index_for_address_(0), + handler_(nullptr), + socket_(_io), + recv_buffer_(recv_buffer_size, 0), + address_(_address), + multicast_address_(_multicast_address), + is_requiring_link_(_is_requiring_link) { + } + ~netlink_connector() {} + + void register_net_if_changes_handler(const net_if_changed_handler_t& _handler); + void unregister_net_if_changes_handler(); + + void start(); + void stop(); + +private: + bool has_address(struct ifaddrmsg * ifa_struct, + size_t length, + const unsigned int address); + void send_ifa_request(std::uint32_t _retry = 0); + void send_ifi_request(std::uint32_t _retry = 0); + void send_rt_request(std::uint32_t _retry = 0); + void handle_netlink_error(struct nlmsgerr *_error_msg); + + void receive_cbk(boost::system::error_code const &_error, std::size_t _bytes); + void send_cbk(boost::system::error_code const &_error, std::size_t _bytes); + + bool check_sd_multicast_route_match(struct rtmsg* _routemsg, + size_t _length, + std::string* _routename) const; + + std::map<int, unsigned int> net_if_flags_; + int net_if_index_for_address_; + + net_if_changed_handler_t handler_; + + std::mutex socket_mutex_; + boost::asio::basic_raw_socket<nl_protocol> socket_; + + const size_t recv_buffer_size = 16384; + message_buffer_t recv_buffer_; + + boost::asio::ip::address address_; + boost::asio::ip::address multicast_address_; + bool is_requiring_link_; + + static const std::uint32_t max_retries_ = VSOMEIP_MAX_NETLINK_RETRIES; + static const std::uint32_t retry_bit_shift_ = 8; + static const std::uint32_t request_sequence_bitmask_ = 0xFF; + static const std::uint32_t ifa_request_sequence_ = 1; + static const std::uint32_t ifi_request_sequence_ = 2; + static const std::uint32_t rt_request_sequence_ = 3; +}; + +} // namespace vsomeip_v3 + +#endif // __linux__ || ANDROID + +#endif // VSOMEIP_V3_NETLINK_CONNECTOR_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/server_endpoint_impl.hpp new file mode 100644 index 00000000000..1037401e73e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/server_endpoint_impl.hpp @@ -0,0 +1,169 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_SERVER_ENDPOINT_IMPL_HPP_ + +#include <deque> +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <vector> + +#include <boost/array.hpp> + +#include "buffer.hpp" +#include "endpoint_impl.hpp" +#include "tp.hpp" +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +template<typename Protocol> +class server_endpoint_impl: public endpoint_impl<Protocol>, + public std::enable_shared_from_this<server_endpoint_impl<Protocol> > { +public: + typedef typename Protocol::socket socket_type; + typedef typename Protocol::endpoint endpoint_type; + struct endpoint_data_type { + endpoint_data_type(boost::asio::io_context &_io) + : train_(std::make_shared<train>()), + dispatch_timer_(std::make_shared<boost::asio::steady_timer>(_io)), + has_last_departure_(false), + queue_size_(0), + is_sending_(false), + sent_timer_(_io), + io_(_io) { + } + + endpoint_data_type(const endpoint_data_type &&_source) + : train_(_source.train_), + dispatch_timer_(std::make_shared<boost::asio::steady_timer>(_source.io_)), + has_last_departure_(_source.has_last_departure_), + queue_(_source.queue_), + queue_size_(_source.queue_size_), + is_sending_(_source.is_sending_), + sent_timer_(_source.io_), + io_(_source.io_) { + } + + std::shared_ptr<train> train_; + std::map<std::chrono::steady_clock::time_point, + std::deque<std::shared_ptr<train> > > dispatched_trains_; + std::shared_ptr<boost::asio::steady_timer> dispatch_timer_; + std::chrono::steady_clock::time_point last_departure_; + bool has_last_departure_; + + std::deque<std::pair<message_buffer_ptr_t, uint32_t> > queue_; + std::size_t queue_size_; + + bool is_sending_; + boost::asio::steady_timer sent_timer_; + + boost::asio::io_context &io_; + }; + + typedef typename std::map<endpoint_type, endpoint_data_type> target_data_type; + typedef typename target_data_type::iterator target_data_iterator_type; + + server_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~server_endpoint_impl() = default; + + virtual void init(const endpoint_type& _local, boost::system::error_code& _error) = 0; + virtual void stop(); + + bool is_client() const; + void restart(bool _force); + bool is_established() const; + bool is_established_or_connected() const; + void set_established(bool _established); + void set_connected(bool _connected); + bool send(const uint8_t *_data, uint32_t _size); + bool send(const std::vector<byte_t>& _cmd_header, const byte_t *_data, + uint32_t _size); + + void prepare_stop(const endpoint::prepare_stop_handler_t &_handler, + service_t _service); + bool flush(endpoint_type _it); + + size_t get_queue_size() const; + + virtual bool is_reliable() const = 0; + virtual std::uint16_t get_local_port() const = 0; + virtual void set_local_port(uint16_t _port) = 0; + +public: + void connect_cbk(boost::system::error_code const &_error); + void send_cbk(const endpoint_type _key, + boost::system::error_code const &_error, std::size_t _bytes); + void flush_cbk(endpoint_type _key, + const boost::system::error_code &_error_code); + void remove_stop_handler(service_t _service); + +protected: + virtual bool send_intern(endpoint_type _target, const byte_t *_data, + uint32_t _port); + virtual bool send_queued(const target_data_iterator_type _it) = 0; + virtual void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const = 0; + + virtual bool get_default_target(service_t _service, + endpoint_type &_target) const = 0; + + virtual void print_status() = 0; + + typename endpoint_impl<Protocol>::cms_ret_e check_message_size( + const std::uint8_t * const _data, std::uint32_t _size, + const endpoint_type &_target); + bool check_queue_limit(const uint8_t *_data, std::uint32_t _size, + endpoint_data_type &_endpoint_data) const; + bool queue_train(const target_data_iterator_type _it, + const std::shared_ptr<train> &_train); + + void send_segments(const tp::tp_split_messages_t &_segments, + std::uint32_t _separation_time, const endpoint_type &_target); + + target_data_iterator_type find_or_create_target_unlocked(endpoint_type _target); + +protected: + std::mutex clients_mutex_; + std::map<client_t, std::map<session_t, endpoint_type> > clients_; + + target_data_type targets_; + + std::map<service_t, endpoint::prepare_stop_handler_t> prepare_stop_handlers_; + + mutable std::mutex mutex_; + +private: + virtual std::string get_remote_information( + const target_data_iterator_type _queue_iterator) const = 0; + virtual std::string get_remote_information( + const endpoint_type& _remote) const = 0; + virtual bool tp_segmentation_enabled(service_t _service, + instance_t _instance, + method_t _method) const; + + void schedule_train(endpoint_data_type &_target); + void update_last_departure(endpoint_data_type &_data); + + void start_dispatch_timer(target_data_iterator_type _it, + const std::chrono::steady_clock::time_point &_now); + void cancel_dispatch_timer(target_data_iterator_type _it); + + void recalculate_queue_size(endpoint_data_type &_data) const; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_client_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_client_endpoint_impl.hpp new file mode 100644 index 00000000000..9820004cdb0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_client_endpoint_impl.hpp @@ -0,0 +1,114 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TCP_CLIENT_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_TCP_CLIENT_ENDPOINT_IMPL_HPP_ + +#include <chrono> + +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/defines.hpp> +#include "client_endpoint_impl.hpp" +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +typedef client_endpoint_impl< + boost::asio::ip::tcp + > tcp_client_endpoint_base_impl; + +class tcp_client_endpoint_impl: public tcp_client_endpoint_base_impl { +public: + tcp_client_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, + const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~tcp_client_endpoint_impl(); + + void init(); + void start(); + void restart(bool _force); + + std::uint16_t get_local_port() const; + void set_local_port(port_t _port); + + bool get_remote_address(boost::asio::ip::address &_address) const; + std::uint16_t get_remote_port() const; + bool is_reliable() const; + bool is_local() const; + void print_status(); + + void send_cbk(boost::system::error_code const &_error, std::size_t _bytes, + const message_buffer_ptr_t& _sent_msg); +private: + void send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + bool is_magic_cookie(const message_buffer_ptr_t& _recv_buffer, + size_t _offset) const; + void send_magic_cookie(message_buffer_ptr_t &_buffer); + + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes, + const message_buffer_ptr_t& _recv_buffer, + std::size_t _recv_buffer_size); + + void connect(); + void receive(); + void receive(message_buffer_ptr_t _recv_buffer, + std::size_t _recv_buffer_size, + std::size_t _missing_capacity); + void calculate_shrink_count(const message_buffer_ptr_t& _recv_buffer, + std::size_t _recv_buffer_size); + std::string get_address_port_remote() const; + std::string get_address_port_local() const; + void handle_recv_buffer_exception(const std::exception &_e, + const message_buffer_ptr_t& _recv_buffer, + std::size_t _recv_buffer_size); + void set_local_port(); + std::size_t write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + const std::chrono::steady_clock::time_point _start); + std::string get_remote_information() const; + std::shared_ptr<struct timing> get_timing( + const service_t& _service, const instance_t& _instance) const; + std::uint32_t get_max_allowed_reconnects() const; + void max_allowed_reconnects_reached(); + + void wait_until_sent(const boost::system::error_code &_error); + + const std::uint32_t recv_buffer_size_initial_; + message_buffer_ptr_t recv_buffer_; + std::uint32_t shrink_count_; + const std::uint32_t buffer_shrink_threshold_; + + const boost::asio::ip::address remote_address_; + const std::uint16_t remote_port_; + std::chrono::steady_clock::time_point last_cookie_sent_; + const std::chrono::milliseconds send_timeout_; + const std::chrono::milliseconds send_timeout_warning_; + + std::uint32_t tcp_restart_aborts_max_; + std::uint32_t tcp_connect_time_max_; + std::atomic<uint32_t> aborted_restart_count_; + std::chrono::steady_clock::time_point connect_timepoint_; + + boost::asio::steady_timer sent_timer_; + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TCP_CLIENT_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_server_endpoint_impl.hpp new file mode 100644 index 00000000000..dd7b9554cba --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tcp_server_endpoint_impl.hpp @@ -0,0 +1,161 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TCP_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_TCP_SERVER_ENDPOINT_IMPL_HPP_ + +#include <map> +#include <memory> + +#include <boost/asio/ip/tcp.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/export.hpp> +#include "server_endpoint_impl.hpp" + +#include <chrono> + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +typedef server_endpoint_impl< + boost::asio::ip::tcp + > tcp_server_endpoint_base_impl; + +class tcp_server_endpoint_impl: public tcp_server_endpoint_base_impl { + +public: + tcp_server_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~tcp_server_endpoint_impl() = default; + + void init(const endpoint_type& _local, boost::system::error_code& _error); + void start(); + void stop(); + + bool send_to(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_queued(const target_data_iterator_type _it); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + + VSOMEIP_EXPORT bool is_established_to(const std::shared_ptr<endpoint_definition>& _endpoint); + + bool get_default_target(service_t, endpoint_type &) const; + + std::uint16_t get_local_port() const; + void set_local_port(uint16_t _port); + bool is_reliable() const; + bool is_local() const; + + // dummies to implement endpoint_impl interface + // TODO: think about a better design! + void receive(); + void print_status(); + + bool is_suspended() const; +private: + class connection: public std::enable_shared_from_this<connection> { + + public: + typedef std::shared_ptr<connection> ptr; + + static ptr create(const std::weak_ptr<tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_context & _io, + std::chrono::milliseconds _send_timeout); + + ~connection(); + + socket_type & get_socket(); + std::unique_lock<std::mutex> get_socket_lock(); + + void start(); + void stop(); + void receive(); + + void send_queued(const target_data_iterator_type _it); + + void set_remote_info(const endpoint_type &_remote); + std::string get_address_port_remote() const; + std::size_t get_recv_buffer_capacity() const; + + private: + connection(const std::weak_ptr<tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _recv_buffer_size_initial, + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_context &_io, + std::chrono::milliseconds _send_timeout); + bool send_magic_cookie(message_buffer_ptr_t &_buffer); + bool is_magic_cookie(size_t _offset) const; + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes); + void calculate_shrink_count(); + std::string get_address_port_local() const; + void handle_recv_buffer_exception(const std::exception &_e); + std::size_t write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + const std::chrono::steady_clock::time_point _start); + void stop_and_remove_connection(); + void wait_until_sent(const boost::system::error_code &_error); + + std::mutex socket_mutex_; + tcp_server_endpoint_impl::socket_type socket_; + std::weak_ptr<tcp_server_endpoint_impl> server_; + + const uint32_t max_message_size_; + const uint32_t recv_buffer_size_initial_; + + message_buffer_t recv_buffer_; + size_t recv_buffer_size_; + std::uint32_t missing_capacity_; + std::uint32_t shrink_count_; + const std::uint32_t buffer_shrink_threshold_; + + endpoint_type remote_; + boost::asio::ip::address remote_address_; + std::uint16_t remote_port_; + std::atomic<bool> magic_cookies_enabled_; + std::chrono::steady_clock::time_point last_cookie_sent_; + const std::chrono::milliseconds send_timeout_; + const std::chrono::milliseconds send_timeout_warning_; + }; + + std::mutex acceptor_mutex_; + boost::asio::ip::tcp::acceptor acceptor_; + std::mutex connections_mutex_; + typedef std::map<endpoint_type, connection::ptr> connections_t; + connections_t connections_; + const std::uint32_t buffer_shrink_threshold_; + std::uint16_t local_port_; + const std::chrono::milliseconds send_timeout_; + +private: + void remove_connection(connection *_connection); + void accept_cbk(const connection::ptr& _connection, + boost::system::error_code const &_error); + std::string get_remote_information( + const target_data_iterator_type _it) const; + std::string get_remote_information(const endpoint_type& _remote) const; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TCP_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp.hpp new file mode 100644 index 00000000000..ee6b329b1ca --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TP_HPP_ +#define VSOMEIP_V3_TP_HPP_ + +#include <cstdint> +#include <vector> +#include <utility> +#include <memory> + +#include <vsomeip/enumeration_types.hpp> + +#include "buffer.hpp" + +namespace vsomeip_v3 { +namespace tp { + +#define VSOMEIP_TP_HEADER_SIZE 4 +#define VSOMEIP_TP_HEADER_POS_MIN 16 +#define VSOMEIP_TP_HEADER_POS_MAX 19 +#define VSOMEIP_TP_PAYLOAD_POS 20 + +// 28 bit length + 3 bit reserved + 1 bit more segments +typedef std::uint32_t tp_header_t; +typedef std::uint8_t tp_message_type_t; +typedef std::vector<message_buffer_ptr_t> tp_split_messages_t; + +const std::uint8_t TP_FLAG = 0x20; + +class tp { +public: + static inline length_t get_offset(tp_header_t _tp_header) { + return _tp_header & 0xfffffff0; + }; + static inline bool more_segments(tp_header_t _tp_header) { + return _tp_header & 0x1; + }; + static inline bool tp_flag_is_set(tp_message_type_t _msg_type) { + return _msg_type & TP_FLAG; + }; + static inline tp_message_type_t tp_flag_set(message_type_e _msg_type) { + return static_cast<tp_message_type_t>(_msg_type) | TP_FLAG; + } + static inline message_type_e tp_flag_unset(tp_message_type_t _msg_type) { + return static_cast<message_type_e>(_msg_type & ~TP_FLAG); + } + + static tp_split_messages_t tp_split_message( + const std::uint8_t * const _data, std::uint32_t _size, + std::uint16_t _max_segment_length); + + static const std::uint16_t tp_max_segment_length_ = 1392; +}; + +} // namespace tp +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TP_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_message.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_message.hpp new file mode 100644 index 00000000000..0f943b403ff --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_message.hpp @@ -0,0 +1,65 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TP_MESSAGE_HPP_ +#define VSOMEIP_V3_TP_MESSAGE_HPP_ + +#include <set> +#include <chrono> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> + +#include "buffer.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif +namespace vsomeip_v3 { +namespace tp { + +class tp_message { +public: + tp_message(const byte_t* const _data, std::uint32_t _data_length, + std::uint32_t _max_message_size); + + bool add_segment(const byte_t* const _data, std::uint32_t _data_length); + + message_buffer_t get_message(); + + std::chrono::steady_clock::time_point get_creation_time() const; + +private: + std::string get_message_id(const byte_t* const _data, std::uint32_t _data_length); + bool check_lengths(const byte_t* const _data, std::uint32_t _data_length, + length_t _segment_size, bool _more_fragments); +private: + std::chrono::steady_clock::time_point timepoint_creation_; + std::uint32_t max_message_size_; + std::uint32_t current_message_size_; + bool last_segment_received_; + + struct segment_t { + segment_t(std::uint32_t _start, std::uint32_t _end) : + start_(_start), + end_(_end) { + } + + bool operator<(const segment_t& _other) const { + return start_ < _other.start_ + || ((start_ >= _other.start_) && (end_ < _other.end_)); + }; + + std::uint32_t start_; + std::uint32_t end_; + }; + std::set<segment_t> segments_; + message_buffer_t message_; +}; + +} // namespace tp +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TP_MESSAGE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_reassembler.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_reassembler.hpp new file mode 100644 index 00000000000..5c8936ae12b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/tp_reassembler.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TP_REASSEMBLER_HPP_ +#define VSOMEIP_V3_TP_REASSEMBLER_HPP_ + +#include <cstdint> +#include <map> +#include <mutex> +#include <memory> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/address.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/primitive_types.hpp> + +#include "tp_message.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { +namespace tp { + +class tp_reassembler : public std::enable_shared_from_this<tp_reassembler> { +public: + tp_reassembler(std::uint32_t _max_message_size, boost::asio::io_context &_io); + /** + * @return Returns a pair consisting of a bool and a message_buffer_t. The + * value of the bool is set to true if the pair contains a finished message + */ + std::pair<bool, message_buffer_t> process_tp_message( + const byte_t* const _data, std::uint32_t _data_size, + const boost::asio::ip::address& _address, std::uint16_t _port); + bool cleanup_unfinished_messages(); + void stop(); + +private: + void cleanup_timer_start(bool _force); + void cleanup_timer_start_unlocked(bool _force); + void cleanup_timer_cbk(const boost::system::error_code _error); + +private: + const std::uint32_t max_message_size_; + std::mutex cleanup_timer_mutex_; + bool cleanup_timer_running_; + boost::asio::steady_timer cleanup_timer_; + + std::mutex mutex_; + std::map<boost::asio::ip::address, std::map<std::uint16_t, + std::map<std::uint64_t, std::pair<session_t, tp_message>>>> tp_messages_; +}; + +} // namespace tp +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TP_REASSEMBLER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_client_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_client_endpoint_impl.hpp new file mode 100644 index 00000000000..02d7cd02844 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_client_endpoint_impl.hpp @@ -0,0 +1,87 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_UDP_CLIENT_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_UDP_CLIENT_ENDPOINT_IMPL_HPP_ + +#include <memory> + +#include <boost/asio/strand.hpp> +#include <boost/asio/ip/udp.hpp> + +#include <vsomeip/defines.hpp> + +#include "client_endpoint_impl.hpp" +#include "tp_reassembler.hpp" + +namespace vsomeip_v3 { + +class endpoint_adapter; + +typedef client_endpoint_impl< + boost::asio::ip::udp + > udp_client_endpoint_base_impl; + +class udp_client_endpoint_impl: virtual public udp_client_endpoint_base_impl { + +public: + udp_client_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, + const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~udp_client_endpoint_impl(); + + void start(); + void restart(bool _force); + + void receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes, const message_buffer_ptr_t& _recv_buffer); + + std::uint16_t get_local_port() const; + void set_local_port(port_t _port); + + bool get_remote_address(boost::asio::ip::address &_address) const; + std::uint16_t get_remote_port() const; + bool is_local() const; + + void print_status(); + bool is_reliable() const; + + void send_cbk(boost::system::error_code const &_error, + std::size_t _bytes, const message_buffer_ptr_t &_sent_msg); +private: + void send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + void connect(); + void receive(); + void set_local_port(); + std::string get_address_port_remote() const; + std::string get_address_port_local() const; + std::string get_remote_information() const; + bool tp_segmentation_enabled( + service_t _service, + instance_t _instance, + method_t _method) const; + std::uint32_t get_max_allowed_reconnects() const; + void max_allowed_reconnects_reached(); + +private: + const boost::asio::ip::address remote_address_; + const std::uint16_t remote_port_; + const int udp_receive_buffer_size_; + std::shared_ptr<tp::tp_reassembler> tp_reassembler_; + + std::mutex last_sent_mutex_; + std::chrono::steady_clock::time_point last_sent_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_UDP_CLIENT_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl.hpp new file mode 100644 index 00000000000..9cddac1dcc9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl.hpp @@ -0,0 +1,157 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_HPP_ + +#include <boost/asio/ip/udp.hpp> +#include <vsomeip/defines.hpp> + +#include "server_endpoint_impl.hpp" +#include "tp_reassembler.hpp" + +namespace vsomeip_v3 { +typedef server_endpoint_impl< + boost::asio::ip::udp + > udp_server_endpoint_base_impl; + +// callback type to sent messages (SD) +using on_unicast_sent_cbk_t = + std::function<void(const byte_t*, length_t, const boost::asio::ip::address&)>; +// callback type to own multicast messages received +using on_sent_multicast_received_cbk_t = + std::function<void(const byte_t*, length_t, const boost::asio::ip::address&)>; + +class udp_server_endpoint_impl: public udp_server_endpoint_base_impl { + +public: + udp_server_endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration); + virtual ~udp_server_endpoint_impl() = default; + + void init(const endpoint_type& _local, boost::system::error_code& _error); + void start(); + void stop(); + + void receive(); + + bool send_to(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_queued(const target_data_iterator_type _it); + void get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const; + + VSOMEIP_EXPORT void join(const std::string &_address); + VSOMEIP_EXPORT void join_unlocked(const std::string &_address); + VSOMEIP_EXPORT void leave(const std::string &_address); + VSOMEIP_EXPORT void set_multicast_option(const boost::asio::ip::address &_address, + bool _is_join, boost::system::error_code& _error); + + void add_default_target(service_t _service, + const std::string &_address, uint16_t _port); + void remove_default_target(service_t _service); + bool get_default_target(service_t _service, endpoint_type &_target) const; + + std::uint16_t get_local_port() const; + void set_local_port(uint16_t _port); + bool is_local() const; + + void print_status(); + bool is_reliable() const; + + // Callback to sent messages + void set_unicast_sent_callback(const on_unicast_sent_cbk_t& _cbk); + // to own multicast messages received + void set_sent_multicast_received_callback(const on_sent_multicast_received_cbk_t& _cbk); + void set_receive_own_multicast_messages(bool value); + + bool is_joining() const; + +private: + void leave_unlocked(const std::string &_address); + void set_broadcast(); + void receive_unicast(); + void receive_multicast(uint8_t _id); + bool is_joined(const std::string &_address) const; + bool is_joined(const std::string &_address, bool& _received) const; + std::string get_remote_information( + const target_data_iterator_type _it) const; + std::string get_remote_information(const endpoint_type& _remote) const; + + std::string get_address_port_local() const; + bool tp_segmentation_enabled( + service_t _service, + instance_t _instance, + method_t _method) const; + + void on_unicast_received(boost::system::error_code const &_error, + std::size_t _bytes); + + void on_multicast_received(boost::system::error_code const &_error, + std::size_t _bytes, uint8_t _multicast_id, + const boost::asio::ip::address &_destination); + + void on_message_received(boost::system::error_code const &_error, + std::size_t _bytes, + bool _is_multicast, + endpoint_type const &_remote, + message_buffer_t const &_buffer); + + bool is_same_subnet(const boost::asio::ip::address &_address) const; + + void shutdown_and_close(); + void unicast_shutdown_and_close_unlocked(); + void multicast_shutdown_and_close_unlocked(); + +private: + std::shared_ptr<socket_type> unicast_socket_; + endpoint_type unicast_remote_; + message_buffer_t unicast_recv_buffer_; + mutable std::mutex unicast_mutex_; + + bool is_v4_; + + std::shared_ptr<socket_type> multicast_socket_; + std::unique_ptr<endpoint_type> multicast_local_; + endpoint_type multicast_remote_; + message_buffer_t multicast_recv_buffer_; + mutable std::recursive_mutex multicast_mutex_; + uint8_t multicast_id_; + std::map<std::string, bool> joined_; + std::atomic<bool> joined_group_; + + mutable std::mutex default_targets_mutex_; + std::map<service_t, endpoint_type> default_targets_; + + boost::asio::ip::address netmask_; + unsigned short prefix_; + + std::uint16_t local_port_; + + std::shared_ptr<tp::tp_reassembler> tp_reassembler_; + boost::asio::steady_timer tp_cleanup_timer_; + + std::mutex last_sent_mutex_; + std::chrono::steady_clock::time_point last_sent_; + + std::atomic<bool> is_stopped_; + + // to tracking sent messages + on_unicast_sent_cbk_t on_unicast_sent_; + + // to receive own multicast messages + bool receive_own_multicast_messages_; + on_sent_multicast_received_cbk_t on_sent_multicast_received_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl_receive_op.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl_receive_op.hpp new file mode 100644 index 00000000000..5823dcf59a0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/udp_server_endpoint_impl_receive_op.hpp @@ -0,0 +1,369 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ +#define VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ + +#ifdef _WIN32 +#include <ws2def.h> +#endif + +#include <iomanip> +#include <memory> + +#include <boost/asio/ip/udp.hpp> + +#include <vsomeip/internal/logger.hpp> + +#if defined(__QNX__) +#include <netinet/in.h> +#include <sys/socket.h> +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { +namespace udp_endpoint_receive_op { + +typedef boost::asio::ip::udp::socket socket_type_t; +typedef boost::asio::ip::udp::endpoint endpoint_type_t; +typedef std::function< + void (boost::system::error_code const &_error, size_t _size, + std::uint8_t, const boost::asio::ip::address &)> receive_handler_t; + +struct storage : + public std::enable_shared_from_this<storage> +{ + std::recursive_mutex &multicast_mutex_; + std::weak_ptr<socket_type_t> socket_; + endpoint_type_t &sender_; + receive_handler_t handler_; + byte_t *buffer_ = nullptr; + size_t length_; + std::uint8_t multicast_id_; + bool is_v4_; + boost::asio::ip::address destination_; + size_t bytes_; + + storage( + std::recursive_mutex &_multicast_mutex, + std::weak_ptr<socket_type_t> _socket, + endpoint_type_t &_sender, + receive_handler_t _handler, + byte_t *_buffer, + size_t _length, + std::uint8_t _multicast_id, + bool _is_v4, + boost::asio::ip::address _destination, + size_t _bytes + ) : multicast_mutex_(_multicast_mutex), + socket_(_socket), + sender_(_sender), + handler_(_handler), + buffer_(_buffer), + length_(_length), + multicast_id_(_multicast_id), + is_v4_(_is_v4), + destination_(_destination), + bytes_(_bytes) + {} +}; + +std::function<void(boost::system::error_code _error)> +receive_cb (std::shared_ptr<storage> _data) { + return [_data](boost::system::error_code _error) { + _data->sender_ = endpoint_type_t(); // reset + + if (!_error) { + + std::lock_guard<std::recursive_mutex> its_lock(_data->multicast_mutex_); + + auto multicast_socket = _data->socket_.lock(); + if (!multicast_socket) { + VSOMEIP_WARNING << "udp_endpoint_receive_op::receive_cb: multicast_socket with id " << int{_data->multicast_id_} << " has expired!"; + return; + } + + if (!multicast_socket->native_non_blocking()) + multicast_socket->native_non_blocking(true, _error); + + for (;;) { +#ifdef _WIN32 + GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; + LPFN_WSARECVMSG WSARecvMsg; + DWORD its_bytes; + SOCKET its_socket { multicast_socket->native_handle() }; + + WSAIoctl(its_socket, SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, + &WSARecvMsg, sizeof WSARecvMsg, + &its_bytes, NULL, NULL); + + int its_result; + int its_flags { 0 }; + + WSABUF its_buf; + WSAMSG its_msg; + + its_buf.buf = reinterpret_cast<CHAR *>(_data->buffer_); + its_buf.len = _data->length_; + + its_msg.lpBuffers = &its_buf; + its_msg.dwBufferCount = 1; + its_msg.dwFlags = its_flags; + + // Sender & destination address info + union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + + union { + struct cmsghdr cmh; + union { + char v4[CMSG_SPACE(sizeof(struct in_pktinfo))]; + char v6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + } control; + } control_un; + + // Prepare + if (_data->is_v4_) { + its_msg.name = reinterpret_cast<LPSOCKADDR>(&addr); + its_msg.namelen = sizeof(sockaddr_in); + + its_msg.Control.buf = control_un.control.v4; + its_msg.Control.len = sizeof(control_un.control.v4); + } else { + its_msg.name = reinterpret_cast<LPSOCKADDR>(&addr); + its_msg.namelen = sizeof(sockaddr_in6); + + its_msg.Control.buf = control_un.control.v6; + its_msg.Control.len = sizeof(control_un.control.v6); + } + + errno = 0; + its_result = WSARecvMsg(its_socket, &its_msg, &its_bytes, + NULL, NULL); + + _error = boost::system::error_code(its_result < 0 ? errno : 0, + boost::asio::error::get_system_category()); + _data->bytes_ += _error ? 0 : static_cast<size_t>(its_bytes); + + if (_error == boost::asio::error::interrupted) + continue; + + if (_error == boost::asio::error::would_block + || _error == boost::asio::error::try_again) { + + multicast_socket->async_wait( + socket_type_t::wait_read, + receive_cb(_data) + ); + return; + } + + if (_error) + break; + + if (_data->bytes_ == 0) + _error = boost::asio::error::eof; + + // Extract sender & destination addresses + if (_data->is_v4_) { + // sender + boost::asio::ip::address_v4 its_sender_address( + ntohl(addr.v4.sin_addr.s_addr)); + std::uint16_t its_sender_port(ntohs(addr.v4.sin_port)); + _data->sender_ = endpoint_type_t(its_sender_address, its_sender_port); + + // destination + struct in_pktinfo *its_pktinfo_v4; + for (struct cmsghdr *cmsg = WSA_CMSG_FIRSTHDR(&its_msg); + cmsg != NULL; + cmsg = WSA_CMSG_NXTHDR(&its_msg, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len == CMSG_LEN(sizeof(*its_pktinfo_v4))) { + + its_pktinfo_v4 = (struct in_pktinfo*) WSA_CMSG_DATA(cmsg); + if (its_pktinfo_v4) { + _data->destination_ = boost::asio::ip::address_v4( + ntohl(its_pktinfo_v4->ipi_addr.s_addr)); + break; + } + } + } + } else { + boost::asio::ip::address_v6::bytes_type its_bytes; + + // sender + boost::asio::ip::address_v6 its_sender_address; + for (size_t i = 0; i < its_bytes.size(); i++) + its_bytes[i] = addr.v6.sin6_addr.s6_addr[i]; + std::uint16_t its_sender_port(ntohs(addr.v6.sin6_port)); + _data->sender_ = endpoint_type_t(its_sender_address, its_sender_port); + + struct in6_pktinfo *its_pktinfo_v6; + for (struct cmsghdr *cmsg = WSA_CMSG_FIRSTHDR(&its_msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&its_msg, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && cmsg->cmsg_len == WSA_CMSG_LEN(sizeof(*its_pktinfo_v6))) { + + its_pktinfo_v6 = (struct in6_pktinfo *) WSA_CMSG_DATA(cmsg); + if (its_pktinfo_v6) { + for (size_t i = 0; i < its_bytes.size(); i++) + its_bytes[i] = its_pktinfo_v6->ipi6_addr.s6_addr[i]; + _data->destination_ = boost::asio::ip::address_v6(its_bytes); + break; + } + } + } + } + + break; +#else + ssize_t its_result; + int its_flags { 0 }; + + // Create control elements + auto its_header = msghdr(); + struct iovec its_vec[1]; + + // Prepare + its_vec[0].iov_base = _data->buffer_; + its_vec[0].iov_len = _data->length_; + + // Add io buffer + its_header.msg_iov = its_vec; + its_header.msg_iovlen = 1; + + // Sender & destination address info + union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + + union { + struct cmsghdr cmh; + union { + char v4[CMSG_SPACE(sizeof(struct in_pktinfo))]; + char v6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + } control; + } control_un; + + // Prepare + if (_data->is_v4_) { + its_header.msg_name = &addr; + its_header.msg_namelen = sizeof(sockaddr_in); + + its_header.msg_control = control_un.control.v4; + its_header.msg_controllen = sizeof(control_un.control.v4); + } else { + its_header.msg_name = &addr; + its_header.msg_namelen = sizeof(sockaddr_in6); + + its_header.msg_control = control_un.control.v6; + its_header.msg_controllen = sizeof(control_un.control.v6); + } + + // Call recvmsg and handle its result + errno = 0; + its_result = ::recvmsg(multicast_socket->native_handle(), &its_header, its_flags); + + _error = boost::system::error_code(its_result < 0 ? errno : 0, + boost::asio::error::get_system_category()); + _data->bytes_ += _error ? 0 : static_cast<size_t>(its_result); + + if (_error == boost::asio::error::interrupted) + continue; + + if (_error == boost::asio::error::would_block + || _error == boost::asio::error::try_again) { + multicast_socket->async_wait( + socket_type_t::wait_read, + receive_cb(_data) + ); + return; + } + + if (_error) + break; + + if (_data->bytes_ == 0) + _error = boost::asio::error::eof; + + // Extract sender & destination addresses + if (_data->is_v4_) { + // sender + boost::asio::ip::address_v4 its_sender_address( + ntohl(addr.v4.sin_addr.s_addr)); + in_port_t its_sender_port(ntohs(addr.v4.sin_port)); + _data->sender_ = endpoint_type_t(its_sender_address, its_sender_port); + + // destination + struct in_pktinfo *its_pktinfo_v4; + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&its_header); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&its_header, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len == CMSG_LEN(sizeof(*its_pktinfo_v4))) { + + its_pktinfo_v4 = (struct in_pktinfo*) CMSG_DATA(cmsg); + if (its_pktinfo_v4) { + _data->destination_ = boost::asio::ip::address_v4( + ntohl(its_pktinfo_v4->ipi_addr.s_addr)); + break; + } + } + } + } else { + boost::asio::ip::address_v6::bytes_type its_bytes; + + // sender + for (size_t i = 0; i < its_bytes.size(); i++) + its_bytes[i] = addr.v6.sin6_addr.s6_addr[i]; + boost::asio::ip::address_v6 its_sender_address(its_bytes); + in_port_t its_sender_port(ntohs(addr.v6.sin6_port)); + _data->sender_ = endpoint_type_t(its_sender_address, its_sender_port); + + struct in6_pktinfo *its_pktinfo_v6; + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&its_header); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&its_header, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && cmsg->cmsg_len == CMSG_LEN(sizeof(*its_pktinfo_v6))) { + + its_pktinfo_v6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + if (its_pktinfo_v6) { + for (size_t i = 0; i < its_bytes.size(); i++) + its_bytes[i] = its_pktinfo_v6->ipi6_addr.s6_addr[i]; + _data->destination_ = boost::asio::ip::address_v6(its_bytes); + break; + } + } + } + } + + break; +#endif // _WIN32 + } + } + + // Call the handler + _data->handler_(_error, _data->bytes_, _data->multicast_id_, _data->destination_); + }; +} + +} // namespace udp_endpoint_receive_op +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_UDP_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/virtual_server_endpoint_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/virtual_server_endpoint_impl.hpp new file mode 100644 index 00000000000..555260c2059 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/include/virtual_server_endpoint_impl.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_VIRTUAL_SERVER_ENDPOINT_IMPL_HPP_ +#define VSOMEIP_V3_VIRTUAL_SERVER_ENDPOINT_IMPL_HPP_ + +#include <boost/asio/io_context.hpp> +#include <vsomeip/primitive_types.hpp> +#include "../include/endpoint.hpp" + +namespace vsomeip_v3 { + +class virtual_server_endpoint_impl : public endpoint, public std::enable_shared_from_this<virtual_server_endpoint_impl> { +public: + virtual_server_endpoint_impl( + const std::string &_address, + uint16_t _port, + bool _reliable, + boost::asio::io_context &_io); + + virtual ~virtual_server_endpoint_impl(); + + void start(); + void prepare_stop(const endpoint::prepare_stop_handler_t &_handler, + service_t _service); + void stop(); + + bool is_established() const; + bool is_established_or_connected() const; + void set_established(bool _established); + void set_connected(bool _connected); + + bool send(const byte_t *_data, uint32_t _size); + bool send_to(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + bool send_error(const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size); + void enable_magic_cookies(); + void receive(); + + void add_default_target(service_t _service, + const std::string &_address, uint16_t _port); + void remove_default_target(service_t _service); + void remove_stop_handler(service_t _service); + + bool get_remote_address(boost::asio::ip::address &_address) const; + std::uint16_t get_local_port() const; + void set_local_port(uint16_t _port); + std::uint16_t get_remote_port() const; + bool is_reliable() const; + bool is_local() const; + + void restart(bool _force); + + void register_error_handler(const error_handler_t &_handler); + void print_status(); + + size_t get_queue_size() const; + +private: + std::string address_; + uint16_t port_; + bool reliable_; + + boost::asio::io_context &io_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_VIRTUAL_SERVER_ENDPOINT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/client_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/client_endpoint_impl.cpp new file mode 100644 index 00000000000..fe91ca949d6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/client_endpoint_impl.cpp @@ -0,0 +1,897 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> +#include <sstream> +#include <thread> +#include <limits> + +#include <boost/asio/buffer.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/local/stream_protocol.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/client_endpoint_impl.hpp" +#include "../include/endpoint_host.hpp" +#include "../../utility/include/utility.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +template<typename Protocol> +client_endpoint_impl<Protocol>::client_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, const endpoint_type& _remote, + boost::asio::io_context &_io, const std::shared_ptr<configuration>& _configuration) : + endpoint_impl<Protocol>(_endpoint_host, _routing_host, _io, _configuration), + socket_ {std::make_unique<socket_type>(_io)}, remote_ {_remote}, flush_timer_ {_io}, + connect_timer_ {_io}, connect_timeout_ {VSOMEIP_DEFAULT_CONNECT_TIMEOUT}, + state_ {cei_state_e::CLOSED}, reconnect_counter_ {0}, connecting_timer_ {_io}, + connecting_timeout_ {VSOMEIP_DEFAULT_CONNECTING_TIMEOUT}, + train_ {std::make_shared<train>()}, dispatch_timer_ {_io}, has_last_departure_ {false}, + queue_size_ {0}, was_not_connected_ {false}, is_sending_ {false}, strand_(_io) { + this->local_ = _local; +} + +template<typename Protocol> +client_endpoint_impl<Protocol>::~client_endpoint_impl() { + +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::is_client() const { + + return true; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::is_established() const { + + return state_ == cei_state_e::ESTABLISHED; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::is_established_or_connected() const { + + return (state_ == cei_state_e::ESTABLISHED + || state_ == cei_state_e::CONNECTED); +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::set_established(bool _established) { + + if (_established) { + if (state_ != cei_state_e::CONNECTING) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + state_ = cei_state_e::ESTABLISHED; + } else { + state_ = cei_state_e::CLOSED; + } + } + } else { + state_ = cei_state_e::CLOSED; + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::set_connected(bool _connected) { + + if (_connected) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + state_ = cei_state_e::CONNECTED; + } else { + state_ = cei_state_e::CLOSED; + } + } else { + state_ = cei_state_e::CLOSED; + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::prepare_stop( + const endpoint::prepare_stop_handler_t &_handler, service_t _service) { + + (void) _handler; + (void) _service; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::stop() { + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + endpoint_impl<Protocol>::sending_blocked_ = true; + // delete unsent messages + queue_.clear(); + queue_size_ = 0; + } + { + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + boost::system::error_code ec; + connect_timer_.cancel(ec); + } + connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; + + // bind to strand as stop() might be called from different thread + strand_.dispatch(std::bind(&client_endpoint_impl::shutdown_and_close_socket, + this->shared_from_this(), + false) + ); +} + +template<typename Protocol> +std::pair<message_buffer_ptr_t, uint32_t> +client_endpoint_impl<Protocol>::get_front() { + + std::pair<message_buffer_ptr_t, uint32_t> its_entry; + if (queue_.size()) + its_entry = queue_.front(); + + return its_entry; +} + + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::send_to( + const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, + uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + VSOMEIP_ERROR << "Clients endpoints must not be used to " + << "send to explicitely specified targets"; + return false; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::send_error( + const std::shared_ptr<endpoint_definition> _target, const byte_t *_data, + uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + VSOMEIP_ERROR << "Clients endpoints must not be used to " + << "send errors to explicitly specified targets"; + return false; +} + + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::send(const uint8_t *_data, uint32_t _size) { + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + bool must_depart(false); + auto its_now(std::chrono::steady_clock::now()); + +#if 0 + std::stringstream msg; + msg << "cei::send: "; + for (uint32_t i = 0; i < _size; i++) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_DEBUG << msg.str(); +#endif + + if (endpoint_impl<Protocol>::sending_blocked_ || + !check_queue_limit(_data, _size)) { + return false; + } + switch (check_message_size(_data, _size)) { + case endpoint_impl<Protocol>::cms_ret_e::MSG_WAS_SPLIT: + return true; + break; + case endpoint_impl<Protocol>::cms_ret_e::MSG_TOO_BIG: + return false; + break; + case endpoint_impl<Protocol>::cms_ret_e::MSG_OK: + default: + break; + } + + // STEP 1: Cancel dispatch timer + cancel_dispatch_timer(); + + // STEP 3: Get configured timings + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const service_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + + std::chrono::nanoseconds its_debouncing(0), its_retention(0); + get_configured_times_from_endpoint(its_service, its_method, + &its_debouncing, &its_retention); + + // STEP 4: Check if the passenger enters an empty train + const std::pair<service_t, method_t> its_identifier = std::make_pair( + its_service, its_method); + if (train_->passengers_.empty()) { + train_->departure_ = its_now + its_retention; // latest possible + } else { + // STEP 4.1: Check whether the current train already contains the message + if (train_->passengers_.end() != train_->passengers_.find(its_identifier)) { + must_depart = true; + } else { + // STEP 5: Check whether the current message fits into the current train + if (train_->buffer_->size() + _size > endpoint_impl<Protocol>::max_message_size_) { + must_depart = true; + } else { + // STEP 6: Check debouncing time + if (its_debouncing > train_->minimal_max_retention_time_) { + // train's latest departure would already undershot new + // passenger's debounce time + must_depart = true; + } else { + if (its_now + its_debouncing > train_->departure_) { + // train departs earlier as the new passenger's debounce + // time allows + must_depart = true; + } else { + // STEP 7: Check maximum retention time + if (its_retention < train_->minimal_debounce_time_) { + // train's earliest departure would already exceed + // the new passenger's retention time. + must_depart = true; + } else { + if (its_now + its_retention < train_->departure_) { + train_->departure_ = its_now + its_retention; + } + } + } + } + } + } + } + + // STEP 8: if necessary, send current buffer and create a new one + if (must_depart) { + // STEP 8.1: check if debounce time would be undershot here if the train + // departs. Schedule departure of current train and create a new one. + schedule_train(); + + train_ = std::make_shared<train>(); + train_->departure_ = its_now + its_retention; + } + + // STEP 9: insert current message buffer + train_->buffer_->insert(train_->buffer_->end(), _data, _data + _size); + train_->passengers_.insert(its_identifier); + // STEP 9.1: update the trains minimal debounce time if necessary + if (its_debouncing < train_->minimal_debounce_time_) { + train_->minimal_debounce_time_ = its_debouncing; + } + // STEP 9.2: update the trains minimal maximum retention time if necessary + if (its_retention < train_->minimal_max_retention_time_) { + train_->minimal_max_retention_time_ = its_retention; + } + + // STEP 10: restart dispatch timer with next departure time + start_dispatch_timer(its_now); + + return true; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::tp_segmentation_enabled( + service_t /*_service*/, instance_t /*_instance*/, method_t /*_method*/) const { + + return false; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::send_segments( + const tp::tp_split_messages_t &_segments, std::uint32_t _separation_time) { + + auto its_now(std::chrono::steady_clock::now()); + + if (_segments.size() == 0) { + return; + } + + const service_t its_service = bithelper::read_uint16_be(&(*(_segments[0]))[VSOMEIP_SERVICE_POS_MIN]); + const service_t its_method = bithelper::read_uint16_be(&(*(_segments[0]))[VSOMEIP_METHOD_POS_MIN]); + + std::chrono::nanoseconds its_debouncing(0), its_retention(0); + get_configured_times_from_endpoint(its_service, its_method, + &its_debouncing, &its_retention); + // update the trains minimal debounce time if necessary + if (its_debouncing < train_->minimal_debounce_time_) { + train_->minimal_debounce_time_ = its_debouncing; + } + // update the trains minimal maximum retention time if necessary + if (its_retention < train_->minimal_max_retention_time_) { + train_->minimal_max_retention_time_ = its_retention; + } + + // We only need to respect the debouncing. There is no need to wait for further + // messages as we will send several now anyway. + if (!train_->passengers_.empty()) { + schedule_train(); + train_ = std::make_shared<train>(); + train_->departure_ = its_now + its_retention; + } + + for (const auto& s : _segments) { + queue_.emplace_back(std::make_pair(s, _separation_time)); + queue_size_ += s->size(); + } + + if (!is_sending_ && !queue_.empty()) { // no writing in progress + // ignore retention time and send immediately as the train is full anyway + auto its_entry = get_front(); + if (its_entry.first) { + is_sending_ = true; + strand_.dispatch(std::bind(&client_endpoint_impl::send_queued, + this->shared_from_this(), its_entry)); + } + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::schedule_train() { + + if (has_last_departure_) { + if (last_departure_ + train_->minimal_debounce_time_ > train_->departure_) { + train_->departure_ = last_departure_ + train_->minimal_debounce_time_; + } + } + + dispatched_trains_[train_->departure_].push_back(train_); +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::send(const std::vector<byte_t>& _cmd_header, + const byte_t *_data, uint32_t _size) { + (void) _cmd_header; + (void) _data; + (void) _size; + return false; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::flush() { + + bool has_queued(true); + bool is_current_train(true); + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + + std::shared_ptr<train> its_train(train_); + if (!dispatched_trains_.empty()) { + + auto its_dispatched = dispatched_trains_.begin(); + if (its_dispatched->first <= its_train->departure_) { + + is_current_train = false; + its_train = its_dispatched->second.front(); + its_dispatched->second.pop_front(); + if (its_dispatched->second.empty()) { + + dispatched_trains_.erase(its_dispatched); + } + } + } + + if (!its_train->buffer_->empty()) { + + queue_train(its_train); + + // Reset current train if necessary + if (is_current_train) { + its_train->reset(); + } + } else { + has_queued = false; + } + + if (!is_current_train || !dispatched_trains_.empty()) { + + auto its_now(std::chrono::steady_clock::now()); + start_dispatch_timer(its_now); + } + + return has_queued; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::connect_cbk( + boost::system::error_code const &_error) { + + if (_error == boost::asio::error::operation_aborted + || endpoint_impl<Protocol>::sending_blocked_) { + VSOMEIP_WARNING << "cei::" << __func__ << ": endpoint stopped" << " endpoint > " << this + << " socket state > " << static_cast<int>(state_.load()); + shutdown_and_close_socket(false); + return; + } + std::shared_ptr<endpoint_host> its_host = this->endpoint_host_.lock(); + if (its_host) { + if (_error && _error != boost::asio::error::already_connected) { + VSOMEIP_WARNING << "cei::" << __func__ << ": restarting socket due to" + << "(" << _error.value() << "):" << _error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + + shutdown_and_close_socket(true); + + if (state_ != cei_state_e::ESTABLISHED) { + state_ = cei_state_e::CLOSED; + its_host->on_disconnect(this->shared_from_this()); + } + if (get_max_allowed_reconnects() == MAX_RECONNECTS_UNLIMITED || + get_max_allowed_reconnects() >= ++reconnect_counter_) { + start_connect_timer(); + } else { + max_allowed_reconnects_reached(); + } + // Double the timeout as long as the maximum allowed is larger + if (connect_timeout_ < VSOMEIP_MAX_CONNECT_TIMEOUT) + connect_timeout_ = (connect_timeout_ << 1); + } else { + if (_error) { + VSOMEIP_WARNING << "cei::" << __func__ << ": connect_cbk attempt " + << "(" << _error.value() << "):" << _error.message() + << " endpoint > " << this << " socket state > " + << static_cast<int>(state_.load()); + } + { + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + connect_timer_.cancel(); + } + connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; // TODO: use config variable + reconnect_counter_ = 0; + if (was_not_connected_) { + was_not_connected_ = false; + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + auto its_entry = get_front(); + if (its_entry.first) { + is_sending_ = true; + strand_.dispatch(std::bind(&client_endpoint_impl::send_queued, + this->shared_from_this(), its_entry)); + VSOMEIP_WARNING + << __func__ << ": resume sending to: " << get_remote_information() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + } + if (state_ != cei_state_e::ESTABLISHED) { + its_host->on_connect(this->shared_from_this()); + } + receive(); + } + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::cancel_and_connect_cbk( + boost::system::error_code const &_error) { + std::size_t operations_cancelled; + { + /* Need this for TCP endpoints for now because we have no + direct control about the point in time the connect has finished */ + std::lock_guard<std::mutex> its_lock(connecting_timer_mutex_); + operations_cancelled = connecting_timer_.cancel(); + } + if (operations_cancelled != 0) { + if (_error) { + VSOMEIP_WARNING << "cei::" << __func__ << ": cancelled " << operations_cancelled + << " operations err: (" << _error.value() + << "): msg: " << _error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + connect_cbk(_error); + } else { + VSOMEIP_INFO << "cei::" << __func__ << " operations_cancelled is 0 endpoint > " + << this << " socket state > " << static_cast<int>(state_.load()); + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::wait_connect_cbk( + boost::system::error_code const &_error) { + + if (!_error && !client_endpoint_impl<Protocol>::sending_blocked_) { + auto self = this->shared_from_this(); + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::wait_connecting_cbk( + boost::system::error_code const &_error) { + + if (!_error && !client_endpoint_impl<Protocol>::sending_blocked_) { + connect_cbk(boost::asio::error::timed_out); + } else if (_error.value() != ECANCELED) { + VSOMEIP_WARNING << "cei::" << __func__ << ": not calling connect_cbk: " + << "sending_blocked_: " << client_endpoint_impl<Protocol>::sending_blocked_ + << " (" << _error.value() << "):" << _error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::send_cbk( + boost::system::error_code const &_error, std::size_t _bytes, + const message_buffer_ptr_t& _sent_msg) { + + (void)_bytes; + + if (!_error) { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + if (queue_.size() > 0) { + queue_size_ -= queue_.front().first->size(); + queue_.pop_front(); + + update_last_departure(); + + if (queue_.empty()) + is_sending_ = false; + else { + auto its_entry = get_front(); + if (its_entry.first) { + send_queued(its_entry); + } + } + } + return; + } else if (_error == boost::asio::error::broken_pipe) { + state_ = cei_state_e::CLOSED; + bool stopping(false); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + stopping = endpoint_impl<Protocol>::sending_blocked_; + if (stopping) { + queue_.clear(); + queue_size_ = 0; + } else { + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_sent_msg && _sent_msg->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_WARNING << "cei::send_cbk received error: " + << _error.message() << " (" << std::dec + << _error.value() << ") " << get_remote_information() + << " " << std::dec << queue_.size() + << " " << std::dec << queue_size_ << " (" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "]" + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + } + if (!stopping) { + print_status(); + } + was_not_connected_ = true; + shutdown_and_close_socket(true); + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); + } else if (_error == boost::asio::error::not_connected + || _error == boost::asio::error::bad_descriptor + || _error == boost::asio::error::no_permission) { + state_ = cei_state_e::CLOSED; + if (_error == boost::asio::error::no_permission) { + VSOMEIP_WARNING << "cei::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + queue_.clear(); + queue_size_ = 0; + } + was_not_connected_ = true; + shutdown_and_close_socket(true); + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); + } else if (_error == boost::asio::error::operation_aborted) { + VSOMEIP_WARNING << "cei::send_cbk received error: " << _error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + // endpoint was stopped + endpoint_impl<Protocol>::sending_blocked_ = true; + shutdown_and_close_socket(false); + } else if (_error == boost::system::errc::destination_address_required) { + VSOMEIP_WARNING << "cei::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + was_not_connected_ = true; + } else { + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_sent_msg && _sent_msg->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_WARNING << "cei::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information() << " " + << " " << std::dec << queue_.size() + << " " << std::dec << queue_size_ << " (" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "]" + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + print_status(); + } + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + is_sending_ = false; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::flush_cbk( + boost::system::error_code const &_error) { + + if (!_error) { + (void) flush(); + } +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::shutdown_and_close_socket(bool _recreate_socket) { + + std::lock_guard<std::mutex> its_lock(socket_mutex_); + shutdown_and_close_socket_unlocked(_recreate_socket); +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::shutdown_and_close_socket_unlocked(bool _recreate_socket) { + + if (socket_->is_open()) { +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (-1 == fcntl(socket_->native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "cei::shutdown_and_close_socket_unlocked: socket/handle closed already '" + << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_remote_information() + << " endpoint > " << this; + } +#endif + boost::system::error_code its_error; + socket_->shutdown(Protocol::socket::shutdown_both, its_error); + if (its_error) { + VSOMEIP_WARNING << "cei::" << __func__ << ": socket shutdown error " + << "(" << its_error.value() << "): " << its_error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + socket_->close(its_error); + if (its_error) { + VSOMEIP_WARNING << "cei::" << __func__ << ": socket close error " + << "(" << its_error.value() << "): " << its_error.message() + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + } else { + VSOMEIP_WARNING << "cei::" << __func__ << ": socket was not open " + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } + + state_ = cei_state_e::CLOSED; + + if (_recreate_socket) { + socket_.reset(new socket_type(endpoint_impl<Protocol>::io_)); + VSOMEIP_WARNING << "cei::" << __func__ << ": socket has been reset " + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } else { + VSOMEIP_INFO << "cei::" << __func__ << ": not recreating socket " + << " endpoint > " << this << " socket state > " << static_cast<int>(state_.load()); + } +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::get_remote_address( + boost::asio::ip::address &_address) const { + + (void)_address; + return false; +} + +template<typename Protocol> +std::uint16_t client_endpoint_impl<Protocol>::get_remote_port() const { + + return 0; +} + +template<typename Protocol> +std::uint16_t client_endpoint_impl<Protocol>::get_local_port() const { + + return 0; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::set_local_port(port_t _port) { + + (void)_port; // overwritten in IP endpoints +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::start_connect_timer() { + + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + connect_timer_.expires_from_now( + std::chrono::milliseconds(connect_timeout_)); + connect_timer_.async_wait( + std::bind(&client_endpoint_impl<Protocol>::wait_connect_cbk, + this->shared_from_this(), std::placeholders::_1)); +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::start_connecting_timer() { + + std::lock_guard<std::mutex> its_lock(connecting_timer_mutex_); + connecting_timer_.expires_from_now( + std::chrono::milliseconds(connecting_timeout_)); + connecting_timer_.async_wait( + std::bind(&client_endpoint_impl<Protocol>::wait_connecting_cbk, + this->shared_from_this(), std::placeholders::_1)); +} + +template<typename Protocol> +typename endpoint_impl<Protocol>::cms_ret_e client_endpoint_impl<Protocol>::check_message_size( + const std::uint8_t * const _data, std::uint32_t _size) { + + typename endpoint_impl<Protocol>::cms_ret_e ret(endpoint_impl<Protocol>::cms_ret_e::MSG_OK); + if (endpoint_impl<Protocol>::max_message_size_ != MESSAGE_SIZE_UNLIMITED + && _size > endpoint_impl<Protocol>::max_message_size_) { + if (endpoint_impl<Protocol>::is_supporting_someip_tp_ && _data != nullptr) { + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + instance_t its_instance = this->get_instance(its_service); + + if (its_instance != ANY_INSTANCE) { + if (tp_segmentation_enabled(its_service, its_instance, its_method)) { + std::uint16_t its_max_segment_length; + std::uint32_t its_separation_time; + this->configuration_->get_tp_configuration( + its_service, its_instance, its_method, true, + its_max_segment_length, its_separation_time); + send_segments(tp::tp::tp_split_message(_data, _size, + its_max_segment_length), its_separation_time); + return endpoint_impl<Protocol>::cms_ret_e::MSG_WAS_SPLIT; + } + } + } + VSOMEIP_ERROR << "cei::check_message_size: Dropping to big message (" + << std::dec << _size << " Bytes). Maximum allowed message size is: " + << endpoint_impl<Protocol>::max_message_size_ << " Bytes."; + ret = endpoint_impl<Protocol>::cms_ret_e::MSG_TOO_BIG; + } + return ret; +} + +template<typename Protocol> +bool client_endpoint_impl<Protocol>::check_queue_limit(const uint8_t *_data, std::uint32_t _size) const { + + if (endpoint_impl<Protocol>::queue_limit_ != QUEUE_SIZE_UNLIMITED + && (queue_size_ + _size > endpoint_impl<Protocol>::queue_limit_ + || queue_size_ + _size < _size)) { // overflow protection + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_size >= VSOMEIP_SESSION_POS_MAX) { + // this will yield wrong IDs for local communication as the commands + // are prepended to the actual payload + // it will print: + // (lowbyte service ID + highbyte methoid) + // [(Command + lowerbyte sender's client ID). + // highbyte sender's client ID + lowbyte command size. + // lowbyte methodid + highbyte vsomeip length] + its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_ERROR << "cei::check_queue_limit: queue size limit (" << std::dec + << endpoint_impl<Protocol>::queue_limit_ + << ") reached. Dropping message (" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "] " + << "queue_size: " << std::dec << queue_size_ + << " data size: " << std::dec << _size; + return false; + } + return true; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::queue_train( + const std::shared_ptr<train> &_train) { + + queue_size_ += _train->buffer_->size(); + queue_.emplace_back(_train->buffer_, 0); + + if (!is_sending_ && !queue_.empty()) { // no writing in progress + auto its_entry = get_front(); + if (its_entry.first) { + is_sending_ = true; + strand_.dispatch(std::bind(&client_endpoint_impl::send_queued, + this->shared_from_this(), its_entry)); + } + } +} + +template<typename Protocol> +size_t client_endpoint_impl<Protocol>::get_queue_size() const { + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + return queue_size_; +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::start_dispatch_timer( + const std::chrono::steady_clock::time_point &_now) { + + // Choose the next train + std::shared_ptr<train> its_train(train_); + if (!dispatched_trains_.empty()) { + + auto its_dispatched = dispatched_trains_.begin(); + if (its_dispatched->first < its_train->departure_) { + + its_train = its_dispatched->second.front(); + } + } + + std::chrono::nanoseconds its_offset; + if (its_train->departure_ > _now) { + + its_offset = std::chrono::duration_cast<std::chrono::nanoseconds>( + its_train->departure_ - _now); + } else { // already departure time + + its_offset = std::chrono::nanoseconds::zero(); + } + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + dispatch_timer_.expires_from_now(its_offset); +#else + dispatch_timer_.expires_from_now( + std::chrono::duration_cast< + std::chrono::steady_clock::duration>(its_offset)); +#endif + dispatch_timer_.async_wait( + std::bind(&client_endpoint_impl<Protocol>::flush_cbk, + this->shared_from_this(), std::placeholders::_1)); +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::cancel_dispatch_timer() { + + boost::system::error_code ec; + dispatch_timer_.cancel(ec); +} + +template<typename Protocol> +void client_endpoint_impl<Protocol>::update_last_departure() { + + last_departure_ = std::chrono::steady_clock::now(); + has_last_departure_ = true; +} + +// Instantiate template +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +template class client_endpoint_impl<boost::asio::local::stream_protocol>; +#endif +template class client_endpoint_impl<boost::asio::ip::tcp>; +template class client_endpoint_impl<boost::asio::ip::udp>; + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/credentials.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/credentials.cpp new file mode 100644 index 00000000000..63631991375 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/credentials.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(__linux__) || defined(ANDROID) + +#include <cerrno> +#include <cstring> +#include <sys/socket.h> + +#include "../include/credentials.hpp" + +#include <vsomeip/internal/logger.hpp> +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif + +namespace vsomeip_v3 { + +void credentials::activate_credentials(const int _fd) { + int optval = 1; + if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Activating socket option for receiving " + << "credentials failed."; + } +} + +void credentials::deactivate_credentials(const int _fd) { + int optval = 0; + if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Deactivating socket option for receiving " + << "credentials failed."; + } +} + +boost::optional<credentials::received_t> credentials::receive_credentials(const int _fd) { + struct msghdr msgh; + struct iovec iov[2]; + union { + struct cmsghdr cmh; + char control[CMSG_SPACE(sizeof(struct ucred))]; + } control_un; + + // We don't need address of peer as we using connect + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + // Set fields of 'msgh' to point to buffer used to receive (real) data read by recvmsg() + msgh.msg_iov = iov; + msgh.msg_iovlen = 2; + + // Set 'msgh' fields to describe 'control_un' + msgh.msg_control = control_un.control; + msgh.msg_controllen = sizeof(control_un.control); + + // Sender client_id and client_host_length will be received as data + client_t client = VSOMEIP_ROUTING_CLIENT; + uint8_t client_host_length(0); + iov[0].iov_base = &client; + iov[0].iov_len = sizeof(client_t); + iov[1].iov_base = &client_host_length; + iov[1].iov_len = sizeof(uint8_t); + + // Set 'control_un' to describe ancillary data that we want to receive + control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + control_un.cmh.cmsg_level = SOL_SOCKET; + control_un.cmh.cmsg_type = SCM_CREDENTIALS; + + // Receive client_id plus client_host_length plus ancillary data + ssize_t nr = recvmsg(_fd, &msgh, 0); + if (nr == -1) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving credentials failed. No data. errno: " << std::strerror(errno); + return boost::none; + } + + struct cmsghdr* cmhp = CMSG_FIRSTHDR(&msgh); + if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred)) + || cmhp->cmsg_level != SOL_SOCKET || cmhp->cmsg_type != SCM_CREDENTIALS) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving credentials failed. Invalid data."; + return boost::none; + } + + // Use the implicitly-defined copy constructor + struct ucred ucred = *reinterpret_cast<struct ucred*>(CMSG_DATA(cmhp)); + + msgh.msg_iov = iov; + msgh.msg_iovlen = 1; + msgh.msg_control = nullptr; + msgh.msg_controllen = 0; + + // Receive client_host as data + std::string client_host(client_host_length, '\0'); + iov[0].iov_base = &client_host.front(); + iov[0].iov_len = client_host.length(); + + nr = recvmsg(_fd, &msgh, 0); + if (nr == -1) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Receiving client host failed. No data. errno: " << std::strerror(errno); + return boost::none; + } + + return received_t{client, ucred.uid, ucred.gid, client_host}; +} + +void credentials::send_credentials(const int _fd, client_t _client, std::string _client_host) { + struct msghdr msgh; + struct iovec iov[3]; + auto client_host_length = static_cast<uint8_t>(_client_host.length()); + + // data to send + msgh.msg_iov = &iov[0]; + msgh.msg_iovlen = 3; + iov[0].iov_base = &_client; + iov[0].iov_len = sizeof(client_t); + iov[1].iov_base = &client_host_length; + iov[1].iov_len = sizeof(uint8_t); + iov[2].iov_base = &_client_host[0]; + iov[2].iov_len = client_host_length; + + // destination not needed as we use connect + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + // credentials not need to set explicitly + msgh.msg_control = NULL; + msgh.msg_controllen = 0; + + // send client id with credentials + ssize_t ns = sendmsg(_fd, &msgh, 0); + if (ns == -1) { + VSOMEIP_ERROR << __func__ << ": vSomeIP Security: Sending credentials failed. errno: " << std::strerror(errno); + } +} + +} // namespace vsomeip_v3 + +#endif // __linux__ || ANDROID diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_definition.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_definition.cpp new file mode 100644 index 00000000000..ff6ff7bdccd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_definition.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/constants.hpp> + +#include "../include/endpoint_definition.hpp" + +namespace vsomeip_v3 { + +std::map<std::tuple<service_t, instance_t, boost::asio::ip::address, uint16_t, bool>, + std::shared_ptr<endpoint_definition> > endpoint_definition::definitions_; + +std::mutex endpoint_definition::definitions_mutex_; + +std::shared_ptr<endpoint_definition> +endpoint_definition::get(const boost::asio::ip::address &_address, + uint16_t _port, bool _is_reliable, service_t _service, instance_t _instance) { + auto key = std::make_tuple(_service, _instance, _address, _port, _is_reliable); + std::lock_guard<std::mutex> its_lock(definitions_mutex_); + std::shared_ptr<endpoint_definition> its_result; + + auto found_endpoint = definitions_.find(key); + if (found_endpoint != definitions_.end()) { + its_result = found_endpoint->second; + } + + if (!its_result) { + its_result = std::make_shared<endpoint_definition>( + _address, _port, _is_reliable); + definitions_[key] = its_result; + } + + return its_result; +} + +endpoint_definition::endpoint_definition( + const boost::asio::ip::address &_address, uint16_t _port, + bool _is_reliable) + : address_(_address), port_(_port), remote_port_(_port), + is_reliable_(_is_reliable) { +} + +const boost::asio::ip::address & endpoint_definition::get_address() const { + return address_; +} + +uint16_t endpoint_definition::get_port() const { + return port_; +} + +bool endpoint_definition::is_reliable() const { + return is_reliable_; +} + +uint16_t endpoint_definition::get_remote_port() const { + return remote_port_; +} + +void endpoint_definition::set_remote_port(uint16_t _port) { + remote_port_ = _port; +} + + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_impl.cpp new file mode 100644 index 00000000000..b69943bca2f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_impl.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/local/stream_protocol.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_host.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../include/endpoint_impl.hpp" + +namespace vsomeip_v3 { + +template<typename Protocol> +endpoint_impl<Protocol>::endpoint_impl(const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) : + io_(_io), endpoint_host_(_endpoint_host), routing_host_(_routing_host), + is_supporting_magic_cookies_(false), has_enabled_magic_cookies_(false), use_count_(0), + sending_blocked_(false), configuration_(_configuration), is_supporting_someip_tp_(false) { +} + +template<typename Protocol> +void endpoint_impl<Protocol>::enable_magic_cookies() { + has_enabled_magic_cookies_ = is_supporting_magic_cookies_; +} + +template<typename Protocol> +uint32_t endpoint_impl<Protocol>::find_magic_cookie( + byte_t *_buffer, size_t _size) { + bool is_found(false); + uint32_t its_offset = 0xFFFFFFFF; + + uint8_t its_cookie_identifier, its_cookie_type; + + if (is_client()) { + its_cookie_identifier = + static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE); + its_cookie_type = + static_cast<uint8_t>(MAGIC_COOKIE_SERVICE_MESSAGE_TYPE); + } else { + its_cookie_identifier = + static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE); + its_cookie_type = + static_cast<uint8_t>(MAGIC_COOKIE_CLIENT_MESSAGE_TYPE); + } + + do { + its_offset++; // --> first loop has "its_offset = 0" + if (_size > its_offset + 16) { + is_found = (_buffer[its_offset] == 0xFF + && _buffer[its_offset + 1] == 0xFF + && _buffer[its_offset + 2] == its_cookie_identifier + && _buffer[its_offset + 3] == 0x00 + && _buffer[its_offset + 4] == 0x00 + && _buffer[its_offset + 5] == 0x00 + && _buffer[its_offset + 6] == 0x00 + && _buffer[its_offset + 7] == 0x08 + && _buffer[its_offset + 8] == 0xDE + && _buffer[its_offset + 9] == 0xAD + && _buffer[its_offset + 10] == 0xBE + && _buffer[its_offset + 11] == 0xEF + && _buffer[its_offset + 12] == 0x01 + && _buffer[its_offset + 13] == 0x01 + && _buffer[its_offset + 14] == its_cookie_type + && _buffer[its_offset + 15] == 0x00); + } else { + break; + } + + } while (!is_found); + + return (is_found ? its_offset : 0xFFFFFFFF); +} + +template<typename Protocol> +void endpoint_impl<Protocol>::add_default_target( + service_t, const std::string &, uint16_t) { +} + +template<typename Protocol> +void endpoint_impl<Protocol>::remove_default_target(service_t) { +} + +template<typename Protocol> +void endpoint_impl<Protocol>::remove_stop_handler(service_t) { +} + +template<typename Protocol> +void endpoint_impl<Protocol>::register_error_handler(const error_handler_t &_error_handler) { + std::lock_guard<std::mutex> its_lock(error_handler_mutex_); + this->error_handler_ = _error_handler; +} + +template<typename Protocol> +instance_t endpoint_impl<Protocol>::get_instance(service_t _service) { + + instance_t its_instance(0xFFFF); + + auto its_host = endpoint_host_.lock(); + if (its_host) + its_instance = its_host->find_instance(_service, this); + + return its_instance; +} + +// Instantiate template +#if defined(__linux__) || defined(__QNX__) +template class endpoint_impl<boost::asio::local::stream_protocol>; +#endif + +template class endpoint_impl<boost::asio::ip::tcp>; +template class endpoint_impl<boost::asio::ip::udp>; + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_base.cpp new file mode 100644 index 00000000000..f13b41839f5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_base.cpp @@ -0,0 +1,418 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/endpoint_manager_base.hpp" + +#include <vsomeip/internal/logger.hpp> +#include "../include/local_tcp_client_endpoint_impl.hpp" +#include "../include/local_tcp_server_endpoint_impl.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../protocol/include/config_command.hpp" +#include "../../routing/include/routing_manager_base.hpp" +#include "../../utility/include/utility.hpp" + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include "../include/local_uds_client_endpoint_impl.hpp" +#include "../include/local_uds_server_endpoint_impl.hpp" +#endif + +#include <iomanip> + +namespace vsomeip_v3 { + +endpoint_manager_base::endpoint_manager_base( + routing_manager_base* const _rm, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) + : rm_(_rm), + io_(_io), + configuration_(_configuration), + local_port_(ILLEGAL_PORT) { + + is_local_routing_ = configuration_->is_local_routing(); +} + +std::shared_ptr<endpoint> endpoint_manager_base::create_local(client_t _client) { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + return create_local_unlocked(_client); +} + +void endpoint_manager_base::remove_local(const client_t _client) { + std::shared_ptr<endpoint> its_endpoint(find_local(_client)); + if (its_endpoint) { + its_endpoint->register_error_handler(nullptr); + its_endpoint->stop(); + VSOMEIP_INFO << "Client [" << std::hex << rm_->get_client() << "] is closing connection to [" + << std::hex << _client << "]" << " endpoint > " << its_endpoint; + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + local_endpoints_.erase(_client); + } +} + +std::shared_ptr<endpoint> endpoint_manager_base::find_or_create_local(client_t _client) { + std::shared_ptr<endpoint> its_endpoint {nullptr}; + { + std::scoped_lock its_lock {local_endpoint_mutex_}; + its_endpoint = find_local_unlocked(_client); + if (!its_endpoint) { + its_endpoint = create_local_unlocked(_client); + } + } + if (its_endpoint) { + its_endpoint->start(); + } else { + VSOMEIP_ERROR << __func__ << ": couldn't find or create endpoint for client " << _client; + } + return its_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_base::find_local(client_t _client) { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + return find_local_unlocked(_client); +} + +std::shared_ptr<endpoint> endpoint_manager_base::find_local(service_t _service, + instance_t _instance) { + return find_local(rm_->find_local_client(_service, _instance)); +} + + +std::unordered_set<client_t> endpoint_manager_base::get_connected_clients() const { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + std::unordered_set<client_t> clients; + for (const auto& its_client : local_endpoints_) { + clients.insert(its_client.first); + } + return clients; +} + +std::shared_ptr<endpoint> endpoint_manager_base::create_local_server( + const std::shared_ptr<routing_host> &_routing_host) { + std::shared_ptr<endpoint> its_local_server; + std::stringstream its_path; + its_path << utility::get_base_path(configuration_->get_network()) + << std::hex << rm_->get_client(); + const client_t its_client = rm_->get_client(); + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (is_local_routing_) { + try { + if (-1 == ::unlink(its_path.str().c_str()) && errno != ENOENT) { + VSOMEIP_ERROR << "endpoint_manager_base::init_receiver unlink failed (" + << its_path.str() << "): "<< std::strerror(errno); + } + auto its_tmp {std::make_shared<local_uds_server_endpoint_impl>( + shared_from_this(), _routing_host, + io_, configuration_, false)}; + if (its_tmp) { + boost::asio::local::stream_protocol::endpoint its_local_endpoint(its_path.str()); + boost::system::error_code its_error; + its_tmp->init(its_local_endpoint, its_error); + if (!its_error) { + VSOMEIP_INFO << __func__ << ": Listening @ " << its_path.str(); + its_local_server = its_tmp; + } else { + VSOMEIP_ERROR << "Local UDS server endpoint initialization failed. Client " + << std::hex << std::setw(4) << std::setfill('0') << its_client + << " Path: " << its_path.str() << " Reason: " << its_error.message(); + } + } else { + VSOMEIP_ERROR << "Local UDS server endpoint creation failed. Client " + << std::hex << std::setw(4) << std::setfill('0') << its_client + << " Path: " << its_path.str() << " Reason: out_of_memory"; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + } else { +#else + { +#endif + try { + std::lock_guard<std::mutex> its_lock(create_local_server_endpoint_mutex_); + ::unlink(its_path.str().c_str()); + port_t its_port; + std::set<port_t> its_used_ports; + auto its_address = configuration_->get_routing_guest_address(); + uint32_t its_current_wait_time { 0 }; + + auto its_tmp {std::make_shared<local_tcp_server_endpoint_impl>( + shared_from_this(), _routing_host, io_, configuration_, false)}; + if (its_tmp) { + while (get_local_server_port(its_port, its_used_ports) && !its_local_server) { + boost::asio::ip::tcp::endpoint its_local_endpoint(its_address, its_port); + boost::system::error_code its_error; + its_tmp->init(its_local_endpoint, its_error); + if (!its_error) { + VSOMEIP_INFO << __func__ << ": Listening @ " + << its_address.to_string() << ":" << std::dec << its_port; + + if (rm_->is_routing_manager()) + local_port_ = port_t(configuration_->get_routing_host_port() + 1); + else + local_port_ = port_t(its_port + 1); + VSOMEIP_INFO << __func__ << ": Connecting to other clients from " + << its_address.to_string() << ":" << std::dec << local_port_; + + rm_->set_sec_client_port(local_port_); + + its_local_server = its_tmp; + } else { + its_tmp->deinit(); + if (its_error == boost::asio::error::address_in_use) { + its_used_ports.insert(its_port); + } else { + its_current_wait_time += LOCAL_TCP_PORT_WAIT_TIME; + if (its_current_wait_time > LOCAL_TCP_PORT_MAX_WAIT_TIME) + break; + + std::this_thread::sleep_for( + std::chrono::milliseconds(LOCAL_TCP_PORT_WAIT_TIME)); + } + } + } + + if (its_local_server) { + rm_->add_guest(its_client, its_address, its_port); + } else { + VSOMEIP_ERROR << __func__ << ": Local TCP server endpoint initialization failed. " + << "Client " << std::hex << std::setw(4) << std::setfill('0') << its_client + << " Reason: No local port available!"; + } + } else { + VSOMEIP_ERROR << __func__ << ": Local TCP server endpoint creation failed. " + << "Client " << std::hex << std::setw(4) << std::setfill('0') << its_client + << " Reason: No local port available!"; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + } + + return its_local_server; +} + +void endpoint_manager_base::on_connect(std::shared_ptr<endpoint> _endpoint) { + rm_->on_connect(_endpoint); +} + +void endpoint_manager_base::on_disconnect(std::shared_ptr<endpoint> _endpoint) { + rm_->on_disconnect(_endpoint); +} + +bool endpoint_manager_base::on_bind_error(std::shared_ptr<endpoint> _endpoint, + const boost::asio::ip::address &_remote_address, + uint16_t _remote_port) { + + (void)_endpoint; + (void)_remote_address; + (void)_remote_port; + + return true; +} + +void endpoint_manager_base::on_error( + const byte_t *_data, length_t _length, endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + + (void)_data; + (void)_length; + (void)_receiver; + (void)_remote_address; + (void)_remote_port; +} + +void endpoint_manager_base::release_port(uint16_t _port, bool _reliable) { + (void)_port; + (void)_reliable; + // intentionally left blank +} + +client_t endpoint_manager_base::get_client() const { + return rm_->get_client(); +} + +std::string endpoint_manager_base::get_client_host() const { + return rm_->get_client_host(); +} + +std::map<client_t, std::shared_ptr<endpoint>> +endpoint_manager_base::get_local_endpoints() const { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + return local_endpoints_; +} + +void +endpoint_manager_base::log_client_states() const { + std::vector<std::pair<client_t, size_t> > its_client_queue_sizes; + std::stringstream its_log; + + { + std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_); + for (const auto &e : local_endpoints_) { + size_t its_queue_size = e.second->get_queue_size(); + if (its_queue_size > VSOMEIP_DEFAULT_QUEUE_WARN_SIZE) { + its_client_queue_sizes.push_back( + std::make_pair(e.first, its_queue_size)); + } + } + } + + std::sort(its_client_queue_sizes.begin(), its_client_queue_sizes.end(), + [](const std::pair<client_t, size_t> &_a, + const std::pair<client_t, size_t> &_b) { + return (_a.second > _b.second); + }); + + size_t its_max(std::min(size_t(10), its_client_queue_sizes.size())); + its_log << std::setfill('0'); + for (size_t i = 0; i < its_max; i++) { + its_log << std::hex << std::setw(4) << its_client_queue_sizes[i].first << ":" + << std::dec << its_client_queue_sizes[i].second; + if (i < its_max-1) + its_log << ", "; + } + + if (its_log.str().length() > 0) + VSOMEIP_WARNING << "ICQ: [" << its_log.str() << "]"; +} + +std::shared_ptr<endpoint> +endpoint_manager_base::create_local_unlocked(client_t _client) { + + std::stringstream its_path; + its_path << utility::get_base_path(configuration_->get_network()) + << std::hex << _client; + std::shared_ptr<endpoint> its_endpoint; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (is_local_routing_) { + its_endpoint = std::make_shared<local_uds_client_endpoint_impl>( + shared_from_this(), rm_->shared_from_this(), + boost::asio::local::stream_protocol::endpoint(its_path.str()), + io_, configuration_); + VSOMEIP_INFO << "Client [" << std::hex << rm_->get_client() << "] is connecting to [" + << std::hex << _client << "] at " << its_path.str() << " endpoint > " << its_endpoint; + } else { +#else + { +#endif + boost::asio::ip::address its_local_address, its_remote_address; + port_t its_remote_port; + + bool is_guest = rm_->get_guest(_client, its_remote_address, its_remote_port); + if (is_guest) { + try { + its_local_address = configuration_->get_routing_guest_address(); + its_endpoint = std::make_shared<local_tcp_client_endpoint_impl>( + shared_from_this(), rm_->shared_from_this(), + boost::asio::ip::tcp::endpoint(its_local_address, local_port_), + boost::asio::ip::tcp::endpoint(its_remote_address, its_remote_port), + io_, configuration_); + + VSOMEIP_INFO << "Client [" + << std::hex << std::setw(4) << std::setfill('0') << rm_->get_client() + << "] @ " + << its_local_address.to_string() << ":" << std::dec << local_port_ + << " is connecting to [" + << std::hex << std::setw(4) << std::setfill('0') << _client << "] @ " + << its_remote_address.to_string() << ":" << std::dec << its_remote_port + << " endpoint > " << its_endpoint; + + } catch (...) { + } + } else { + VSOMEIP_ERROR << __func__ + << ": Cannot get guest address of client [" + << std::hex << std::setw(4) << std::setfill('0') + << _client << "]"; + } + } + + if (its_endpoint) { + // Messages sent to the VSOMEIP_ROUTING_CLIENT are meant to be routed to + // external devices. Therefore, its local endpoint must not be found by + // a call to find_local. Thus it must not be inserted to the list of local + // clients. + if (_client != VSOMEIP_ROUTING_CLIENT) { + local_endpoints_[_client] = its_endpoint; + } + rm_->register_client_error_handler(_client, its_endpoint); + } else { + VSOMEIP_WARNING << __func__ << ": (" << std::hex << get_client() + << ") not connected. Ignoring client assignment"; + } + return its_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_base::find_local_unlocked(client_t _client) { + std::shared_ptr<endpoint> its_endpoint; + auto found_endpoint = local_endpoints_.find(_client); + if (found_endpoint != local_endpoints_.end()) { + its_endpoint = found_endpoint->second; + } + return its_endpoint; +} + +instance_t endpoint_manager_base::find_instance( + service_t _service, endpoint* const _endpoint) const { + + (void)_service; + (void)_endpoint; + + return (0xFFFF); +} + +bool +endpoint_manager_base::get_local_server_port(port_t &_port, + const std::set<port_t> &_used_ports) const { + +#define SERVER_PORT_OFFSET 2 + +#ifdef _WIN32 + uid_t its_uid { ANY_UID }; + gid_t its_gid { ANY_GID }; +#else + uid_t its_uid { getuid() }; + gid_t its_gid { getgid() }; +#endif + + auto its_port_ranges = configuration_->get_routing_guest_ports( + its_uid, its_gid); + + if (its_port_ranges.empty()) { + VSOMEIP_WARNING << __func__ << ": No configured port ranges for uid/gid=" + << std::dec << its_uid << '/' << its_gid; + } + + for (const auto &its_range : its_port_ranges) { + for (int r = its_range.first; r < its_range.second; + r += SERVER_PORT_OFFSET) { + + if (_used_ports.find(port_t(r)) == _used_ports.end() + && r != configuration_->get_routing_host_port()) { + + _port = port_t(r); + return true; + } + } + } + + return false; +} + +void endpoint_manager_base::add_multicast_option(const multicast_option_t &_option) { + (void)_option; +} + +void endpoint_manager_base::suspend(void) { + // Nothing to be done for internal endpoints +} +void endpoint_manager_base::resume(void) { + // Nothing to be done for internal endpoints +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_impl.cpp new file mode 100644 index 00000000000..4b2bf17a872 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/endpoint_manager_impl.cpp @@ -0,0 +1,1453 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/endpoint_manager_impl.hpp" + +#include <vsomeip/internal/logger.hpp> + +#include "../include/local_tcp_server_endpoint_impl.hpp" +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include "../include/local_uds_server_endpoint_impl.hpp" +#endif +#include "../include/udp_client_endpoint_impl.hpp" +#include "../include/udp_server_endpoint_impl.hpp" +#include "../include/tcp_client_endpoint_impl.hpp" +#include "../include/tcp_server_endpoint_impl.hpp" +#include "../include/virtual_server_endpoint_impl.hpp" +#include "../include/endpoint_definition.hpp" +#include "../../routing/include/routing_manager_base.hpp" +#include "../../routing/include/routing_manager_impl.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../../utility/include/utility.hpp" +#include "../../utility/include/bithelper.hpp" + + +#include <forward_list> +#include <iomanip> + +#ifndef WITHOUT_SYSTEMD +#include <systemd/sd-daemon.h> +#endif +#define SD_LISTEN_FDS_START 3 + +namespace vsomeip_v3 { + +endpoint_manager_impl::endpoint_manager_impl( + routing_manager_base* const _rm, boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) : + endpoint_manager_base(_rm, _io, _configuration), + is_processing_options_(true), + options_thread_(std::bind(&endpoint_manager_impl::process_multicast_options, this)) { + + local_port_ = port_t(_configuration->get_routing_host_port() + 1); + if (!is_local_routing_) { + VSOMEIP_INFO << __func__ << ": Connecting to other clients from " + << configuration_->get_routing_host_address().to_string() + << ":" << std::dec << local_port_; + } +} + +endpoint_manager_impl::~endpoint_manager_impl() { + + { + std::lock_guard<std::mutex> its_guard(options_mutex_); + is_processing_options_ = false; + options_condition_.notify_one(); + } + options_thread_.join(); +} + +std::shared_ptr<endpoint> endpoint_manager_impl::find_or_create_remote_client( + service_t _service, instance_t _instance, bool _reliable) { + std::shared_ptr<endpoint> its_endpoint; + bool start_endpoint(false); + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + its_endpoint = find_remote_client(_service, _instance, _reliable); + if (!its_endpoint) { + its_endpoint = create_remote_client(_service, _instance, _reliable); + start_endpoint = true; + } + } + if (start_endpoint && its_endpoint + && configuration_->is_someip(_service, _instance)) { + its_endpoint->start(); + } + return its_endpoint; +} + +void endpoint_manager_impl::find_or_create_remote_client( + service_t _service, instance_t _instance) { + std::shared_ptr<endpoint> its_reliable_endpoint; + std::shared_ptr<endpoint> its_unreliable_endpoint; + bool start_reliable_endpoint(false); + bool start_unreliable_endpoint(false); + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + its_reliable_endpoint = find_remote_client(_service, _instance, true); + if (!its_reliable_endpoint) { + its_reliable_endpoint = create_remote_client(_service, _instance, true); + start_reliable_endpoint = true; + } + its_unreliable_endpoint = find_remote_client(_service, _instance, false); + if (!its_unreliable_endpoint) { + its_unreliable_endpoint = create_remote_client(_service, _instance, false); + start_unreliable_endpoint = true; + } + } + const bool is_someip = configuration_->is_someip(_service, _instance); + if (start_reliable_endpoint && its_reliable_endpoint && is_someip) { + its_reliable_endpoint->start(); + } + if (start_unreliable_endpoint && its_unreliable_endpoint && is_someip) { + its_unreliable_endpoint->start(); + } +} + +void endpoint_manager_impl::is_remote_service_known( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, + const boost::asio::ip::address &_reliable_address, + uint16_t _reliable_port, bool* _reliable_known, + const boost::asio::ip::address &_unreliable_address, + uint16_t _unreliable_port, bool* _unreliable_known) const { + + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_service = remote_service_info_.find(_service); + if (found_service != remote_service_info_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + std::shared_ptr<endpoint_definition> its_definition; + if (_reliable_port != ILLEGAL_PORT) { + auto found_reliable = found_instance->second.find(true); + if (found_reliable != found_instance->second.end()) { + its_definition = found_reliable->second; + if (its_definition->get_address() == _reliable_address + && its_definition->get_port() == _reliable_port) { + *_reliable_known = true; + } else { + VSOMEIP_WARNING << "Reliable service endpoint has changed: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec << static_cast<std::uint32_t>(_major) << "." + << _minor << "] old: " + << its_definition->get_address().to_string() << ":" + << its_definition->get_port() << " new: " + << _reliable_address.to_string() << ":" + << _reliable_port; + } + } + } + if (_unreliable_port != ILLEGAL_PORT) { + auto found_unreliable = found_instance->second.find(false); + if (found_unreliable != found_instance->second.end()) { + its_definition = found_unreliable->second; + if (its_definition->get_address() == _unreliable_address + && its_definition->get_port() == _unreliable_port) { + *_unreliable_known = true; + } else { + VSOMEIP_WARNING << "Unreliable service endpoint has changed: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec << static_cast<std::uint32_t>(_major) << "." + << _minor << "] old: " + << its_definition->get_address().to_string() << ":" + << its_definition->get_port() << " new: " + << _unreliable_address.to_string() << ":" + << _unreliable_port; + } + } + } + } + } +} + +void endpoint_manager_impl::add_remote_service_info( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint_definition>& _ep_definition) { + + std::shared_ptr<serviceinfo> its_info; + std::shared_ptr<endpoint> its_endpoint; + bool must_report(false); + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + remote_service_info_[_service][_instance][_ep_definition->is_reliable()] = + _ep_definition; + + if (_ep_definition->is_reliable()) { + its_endpoint = find_remote_client(_service, _instance, true); + must_report = (its_endpoint && its_endpoint->is_established_or_connected()); + if (must_report) + its_info = rm_->find_service(_service, _instance); + } + } + + if (must_report) + static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected( + _service, _instance, its_info->get_major(), its_info->get_minor(), + its_endpoint, false); +} + +void endpoint_manager_impl::add_remote_service_info( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint_definition>& _ep_definition_reliable, + const std::shared_ptr<endpoint_definition>& _ep_definition_unreliable) { + + std::shared_ptr<serviceinfo> its_info; + std::shared_ptr<endpoint> its_reliable, its_unreliable; + bool must_report(false); + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + remote_service_info_[_service][_instance][false] = _ep_definition_unreliable; + remote_service_info_[_service][_instance][true] = _ep_definition_reliable; + + its_unreliable = find_remote_client(_service, _instance, false); + its_reliable = find_remote_client(_service, _instance, true); + + must_report = (its_unreliable && its_unreliable->is_established_or_connected() + && its_reliable && its_reliable->is_established_or_connected()); + + if (must_report) + its_info = rm_->find_service(_service, _instance); + } + + if (must_report) { + static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected( + _service, _instance, its_info->get_major(), its_info->get_minor(), + its_unreliable, false); + static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected( + _service, _instance, its_info->get_major(), its_info->get_minor(), + its_reliable, false); + } +} + +void endpoint_manager_impl::clear_remote_service_info(service_t _service, + instance_t _instance, + bool _reliable) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + const auto found_service = remote_service_info_.find(_service); + if (found_service != remote_service_info_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (found_instance->second.erase(_reliable)) { + if (!found_instance->second.size()) { + found_service->second.erase(found_instance); + if (!found_service->second.size()) { + remote_service_info_.erase(found_service); + } + } + } + } + } +} + +std::shared_ptr<endpoint> +endpoint_manager_impl::create_server_endpoint(uint16_t _port, bool _reliable, bool _start) { + std::shared_ptr<endpoint> its_server_endpoint; + boost::system::error_code its_error; + boost::asio::ip::address its_unicast {configuration_->get_unicast_address()}; + const std::string its_unicast_str {its_unicast.to_string()}; + + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + if (_start) { + if (_reliable) { + auto its_tmp {std::make_shared<tcp_server_endpoint_impl>(shared_from_this(), + rm_->shared_from_this(), io_, configuration_)}; + if (its_tmp) { + boost::asio::ip::tcp::endpoint its_reliable(its_unicast, _port); + its_tmp->init(its_reliable, its_error); + if (!its_error) { + if (configuration_->has_enabled_magic_cookies( + its_unicast_str, _port) || + configuration_->has_enabled_magic_cookies( + "local", _port)) { + its_tmp->enable_magic_cookies(); + } + its_server_endpoint = its_tmp; + } + } + } else { + auto its_tmp {std::make_shared<udp_server_endpoint_impl>(shared_from_this(), + rm_->shared_from_this(), io_, configuration_)}; + if (its_tmp) { + boost::asio::ip::udp::endpoint its_unreliable(its_unicast, _port); + its_tmp->init(its_unreliable, its_error); + if (!its_error) { + its_server_endpoint = its_tmp; + } + } + } + } else { + its_server_endpoint = std::make_shared<virtual_server_endpoint_impl>(its_unicast_str, + _port, _reliable, io_); + } + + if (its_server_endpoint) { + server_endpoints_[_port][_reliable] = its_server_endpoint; + its_server_endpoint->start(); + } else { + VSOMEIP_ERROR << __func__ + << " Server endpoint creation failed." + << " Reason: " << its_error.message() + << " Port: " << _port + << " (" << _reliable << ")"; + } + + return its_server_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_impl::find_server_endpoint( + uint16_t _port, bool _reliable) const { + std::shared_ptr<endpoint> its_endpoint; + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_port = server_endpoints_.find(_port); + if (found_port != server_endpoints_.end()) { + auto found_endpoint = found_port->second.find(_reliable); + if (found_endpoint != found_port->second.end()) { + its_endpoint = found_endpoint->second; + } + } + return its_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_impl::find_or_create_server_endpoint( + uint16_t _port, bool _reliable, bool _start, service_t _service, + instance_t _instance, bool &_is_found, bool _is_multicast) { + std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(_port, + _reliable); + _is_found = false; + if (!its_endpoint) { + its_endpoint = create_server_endpoint(_port, _reliable, _start); + } else { + _is_found = true; + } + if (its_endpoint) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + if (!_is_multicast) { + service_instances_[_service][its_endpoint.get()] = _instance; + } + } + return its_endpoint; +} + +bool endpoint_manager_impl::remove_server_endpoint(uint16_t _port, bool _reliable) { + + std::shared_ptr<endpoint> its_endpoint; + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_port = server_endpoints_.find(_port); + if (found_port != server_endpoints_.end()) { + auto found_reliable = found_port->second.find(_reliable); + if (found_reliable != found_port->second.end()) { + its_endpoint = found_reliable->second; + } + } + } + + if (!is_used_endpoint(its_endpoint.get())) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_port = server_endpoints_.find(_port); + if (found_port != server_endpoints_.end()) { + if (found_port->second.erase(_reliable)) { + if (found_port->second.empty()) { + server_endpoints_.erase(found_port); + } + } + return true; + } + } + + return false; +} + +void +endpoint_manager_impl::clear_client_endpoints( + service_t _service, instance_t _instance, bool _reliable) { + + std::shared_ptr<endpoint> its_endpoint; + + boost::asio::ip::address its_remote_address; + port_t its_local_port(0); + port_t its_remote_port(0); + + bool other_services_reachable_through_endpoint(false); + + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + // Clear client endpoints for remote services (generic and specific ones) + const auto found_service = remote_services_.find(_service); + if (found_service != remote_services_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + const auto found_reliability = found_instance->second.find(_reliable); + if (found_reliability != found_instance->second.end()) { + service_instances_[_service].erase(found_reliability->second.get()); + its_endpoint = found_reliability->second; + found_instance->second.erase(found_reliability); + if (found_instance->second.empty()) { + found_service->second.erase(found_instance); + if (found_service->second.empty()) { + remote_services_.erase(found_service); + } + } + } + } + } + + // Only stop and delete the endpoint if none of the services + // reachable through it is online anymore. + if (its_endpoint) { + for (const auto& service : remote_services_) { + for (const auto& instance : service.second) { + const auto found_reliability = instance.second.find(_reliable); + if (found_reliability != instance.second.end() + && found_reliability->second == its_endpoint) { + other_services_reachable_through_endpoint = true; + break; + } + } + if (other_services_reachable_through_endpoint) { break; } + } + + if (!other_services_reachable_through_endpoint) { + partition_id_t its_partition; + + its_partition = configuration_->get_partition_id(_service, _instance); + + if (_reliable) { + std::shared_ptr<tcp_client_endpoint_impl> its_tcp_client_endpoint = + std::dynamic_pointer_cast<tcp_client_endpoint_impl>(its_endpoint); + if (its_tcp_client_endpoint) { + its_local_port = its_tcp_client_endpoint->get_local_port(); + its_remote_port = its_tcp_client_endpoint->get_remote_port(); + its_tcp_client_endpoint->get_remote_address(its_remote_address); + } + } else { + std::shared_ptr<udp_client_endpoint_impl> its_udp_client_endpoint = + std::dynamic_pointer_cast<udp_client_endpoint_impl>(its_endpoint); + if (its_udp_client_endpoint) { + its_local_port = its_udp_client_endpoint->get_local_port(); + its_remote_port = its_udp_client_endpoint->get_remote_port(); + its_udp_client_endpoint->get_remote_address(its_remote_address); + } + } + const auto found_ip = client_endpoints_.find(its_remote_address); + if (found_ip != client_endpoints_.end()) { + const auto found_port = found_ip->second.find(its_remote_port); + if (found_port != found_ip->second.end()) { + auto found_reliable = found_port->second.find(_reliable); + if (found_reliable != found_port->second.end()) { + const auto found_partition = found_reliable->second.find(its_partition); + if (found_partition != found_reliable->second.end()) { + if (found_partition->second == its_endpoint) { + found_reliable->second.erase(its_partition); + // delete if necessary + if (0 == found_reliable->second.size()) { + found_port->second.erase(_reliable); + if (0 == found_port->second.size()) { + found_ip->second.erase(found_port); + if (0 == found_ip->second.size()) { + client_endpoints_.erase(found_ip); + } + } + } + } + } + } + } + } + } + } + } + if (!other_services_reachable_through_endpoint && its_endpoint) { + release_used_client_port(its_remote_address, its_remote_port, + _reliable, its_local_port); + + its_endpoint->stop(); + } +} + +void endpoint_manager_impl::find_or_create_multicast_endpoint( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port) { + bool is_known_multicast(false); + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + const auto found_service = multicast_info_.find(_service); + if (found_service != multicast_info_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + const auto& endpoint_def = found_instance->second; + if (endpoint_def->get_address() == _address && + endpoint_def->get_port() == _port) { + // Multicast info and endpoint already created before + // This can happen when more than one client subscribe on the same instance! + is_known_multicast = true; + } + } + } + } + const bool is_someip = configuration_->is_someip(_service, _instance); + bool _is_found(false); + // Create multicast endpoint & join multicase group + std::shared_ptr<endpoint> its_endpoint = find_or_create_server_endpoint( + _port, false, is_someip, _service, _instance, _is_found, true); + if (!_is_found) { + // Only save multicast info if we created a new endpoint + // to be able to delete the new endpoint + // as soon as the instance stops offering its service + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + std::shared_ptr<endpoint_definition> endpoint_def = + endpoint_definition::get(_address, _port, false, _service, _instance); + multicast_info_[_service][_instance] = endpoint_def; + } + + if (its_endpoint) { + if (!is_known_multicast) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + service_instances_multicast_[_service][_sender] = _instance; + } + + auto its_udp_server_endpoint = + std::dynamic_pointer_cast<udp_server_endpoint_impl>(its_endpoint); + if (its_udp_server_endpoint) + its_udp_server_endpoint->join(_address.to_string()); + } else { + VSOMEIP_ERROR << "Could not find/create multicast endpoint!"; + } +} + +void endpoint_manager_impl::clear_multicast_endpoints(service_t _service, instance_t _instance) { + std::shared_ptr<endpoint> its_multicast_endpoint; + std::string its_address; + + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + // Clear multicast info and endpoint and multicast instance (remote service) + if (multicast_info_.find(_service) != multicast_info_.end()) { + if (multicast_info_[_service].find(_instance) != multicast_info_[_service].end()) { + its_address = multicast_info_[_service][_instance]->get_address().to_string(); + uint16_t its_port = multicast_info_[_service][_instance]->get_port(); + auto found_port = server_endpoints_.find(its_port); + if (found_port != server_endpoints_.end()) { + auto found_unreliable = found_port->second.find(false); + if (found_unreliable != found_port->second.end()) { + its_multicast_endpoint = found_unreliable->second; + server_endpoints_[its_port].erase(false); + } + if (found_port->second.find(true) == found_port->second.end()) { + server_endpoints_.erase(its_port); + } + } + multicast_info_[_service].erase(_instance); + if (0 >= multicast_info_[_service].size()) { + multicast_info_.erase(_service); + } + (void)remove_instance_multicast(_service, _instance); + } + } + } + if (its_multicast_endpoint) { + auto its_udp_server_endpoint = + std::dynamic_pointer_cast<udp_server_endpoint_impl>(its_multicast_endpoint); + if (its_udp_server_endpoint) + its_udp_server_endpoint->leave(its_address); + + if (!is_used_endpoint(its_multicast_endpoint.get())) + its_multicast_endpoint->stop(); + } +} + +bool endpoint_manager_impl::supports_selective(service_t _service, + instance_t _instance) const { + bool supports_selective(false); + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + const auto its_service = remote_service_info_.find(_service); + if (its_service != remote_service_info_.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + for (const auto& its_reliable : its_instance->second) { + supports_selective |= configuration_-> + supports_selective_broadcasts( + its_reliable.second->get_address()); + } + } + } + return supports_selective; +} + +void endpoint_manager_impl::print_status() const { + // local client endpoints + { + std::map<client_t, std::shared_ptr<endpoint>> lces = get_local_endpoints(); + VSOMEIP_INFO << "status local client endpoints: " << std::dec << lces.size(); + for (const auto& lce : lces) { + lce.second->print_status(); + } + } + + // udp and tcp client endpoints + { + client_endpoints_t its_client_endpoints; + server_endpoints_t its_server_endpoints; + { + std::scoped_lock its_lock {endpoint_mutex_}; + its_client_endpoints = client_endpoints_; + its_server_endpoints = server_endpoints_; + } + VSOMEIP_INFO << "status start remote client endpoints:"; + std::uint32_t num_remote_client_endpoints(0); + // normal endpoints + for (const auto &its_address : its_client_endpoints) { + for (const auto &its_port : its_address.second) { + for (const auto &its_reliability : its_port.second) { + for (const auto &its_partition : its_reliability.second) { + its_partition.second->print_status(); + num_remote_client_endpoints++; + } + } + } + } + VSOMEIP_INFO << "status end remote client endpoints: " << std::dec + << num_remote_client_endpoints; + + VSOMEIP_INFO << "status start server endpoints:"; + std::uint32_t num_server_endpoints(1); + // local server endpoints + static_cast<routing_manager_impl*>(rm_)->print_stub_status(); + + // server endpoints + for (const auto& p : its_server_endpoints) { + for (const auto& ru : p.second ) { + ru.second->print_status(); + num_server_endpoints++; + } + } + VSOMEIP_INFO << "status end server endpoints:" + << std::dec << num_server_endpoints; + } +} + +bool endpoint_manager_impl::create_routing_root(std::shared_ptr<endpoint>& _root, + bool& _is_socket_activated, + const std::shared_ptr<routing_host>& _host) { + + std::stringstream its_endpoint_path_ss; + its_endpoint_path_ss << utility::get_base_path(configuration_->get_network()) + << VSOMEIP_ROUTING_CLIENT; + const std::string its_endpoint_path = its_endpoint_path_ss.str(); + client_t its_routing_host_id = configuration_->get_id(configuration_->get_routing_host_name()); + if (configuration_->is_security_enabled() && get_client() != its_routing_host_id) { + VSOMEIP_ERROR << "endpoint_manager_impl::" << __func__ << ": " + << "Client [" + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << "] does not match the configured routing manager client identifier [" + << std::hex << std::setw(4) << std::setfill('0') + << its_routing_host_id + << "]"; + + return false; + } + + if (configuration_->is_local_routing()) { + int its_socket {0}; + int32_t num_fd {0}; +#ifndef WITHOUT_SYSTEMD + num_fd = sd_listen_fds(0); +#endif + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (num_fd > 1) { + VSOMEIP_ERROR << "Too many file descriptors received by systemd socket activation! num_fd: " << num_fd; + } else if (num_fd == 1) { + its_socket = SD_LISTEN_FDS_START + 0; + VSOMEIP_INFO << "Using native socket created by systemd socket activation! fd: " << its_socket; + if (is_local_routing_) { + try { + auto its_root {std::make_shared <local_uds_server_endpoint_impl>(shared_from_this(), + _host, io_, configuration_, true)}; + if (its_root) { + boost::asio::local::stream_protocol::endpoint its_endpoint(its_endpoint_path); + boost::system::error_code its_error; + + its_root->init(its_endpoint, its_socket, its_error); + if (its_error) { + VSOMEIP_ERROR << "Routing endpoint creation failed. Client ID: " + << std::hex << std::setw(4) << std::setfill('0') + << VSOMEIP_ROUTING_CLIENT << ": " << its_error.message(); + + its_root->deinit(); + return false; + } + + _root = its_root; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + } + _is_socket_activated = true; + } else { + if (is_local_routing_) { + try { + if (-1 == ::unlink(its_endpoint_path.c_str()) && errno != ENOENT) { + VSOMEIP_ERROR << "endpoint_manager_impl::create_local_server unlink failed (" + << its_endpoint_path << "): "<< std::strerror(errno); + } + VSOMEIP_INFO << __func__ << ": Routing root @ " << its_endpoint_path; + + auto its_root {std::make_shared <local_uds_server_endpoint_impl>( + shared_from_this(), _host, io_, configuration_, true)}; + if (its_root) { + boost::asio::local::stream_protocol::endpoint its_endpoint(its_endpoint_path); + boost::system::error_code its_error; + + its_root->init(its_endpoint, its_error); + if (its_error) { + VSOMEIP_ERROR << "Local routing endpoint creation failed. Client ID: " + << std::hex << std::setw(4) << std::setfill('0') + << VSOMEIP_ROUTING_CLIENT << ": " << its_error.message(); + + its_root->deinit(); + return false; + } + + _root = its_root; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + } + _is_socket_activated = false; + } +#else + try { + ::unlink(its_endpoint_path.c_str()); + port_t port = VSOMEIP_INTERNAL_BASE_PORT; + VSOMEIP_INFO << __func__ << ": Routing root @ " << std::dec << port; + + auto its_root {std::make_shared <local_tcp_server_endpoint_impl>(shared_from_this(), _host, + io_, configuration_, true)}; + if (its_root) { + boost::asio::ip::tcp::endpoint its_endpoint(boost::asio::ip::tcp::v4(), port); + boost::system::error_code its_error; + + its_root->init(its_endpoint, its_error); + if (its_error) { + VSOMEIP_ERROR << "Local routing endpoint creation failed. Client ID: " + << std::hex << std::setw(4) << std::setfill('0') + << VSOMEIP_ROUTING_CLIENT << ": " << its_error.message(); + its_root->deinit(); + return false; + } + + _root = its_root; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + + _is_socket_activated = false; +#endif // __linux__ || ANDROID + } else { + try { + auto its_address = configuration_->get_routing_host_address(); + auto its_port = configuration_->get_routing_host_port(); + + VSOMEIP_INFO << __func__ << ": Routing root @ " + << its_address.to_string() << ":" << std::dec << its_port; + + auto its_root {std::make_shared <local_tcp_server_endpoint_impl>(shared_from_this(), _host, + io_, configuration_, true)}; + if (its_root) { + boost::asio::ip::tcp::endpoint its_endpoint(its_address, its_port); + boost::system::error_code its_error; + + int its_retry {0}; + do { + its_root->init(its_endpoint, its_error); + if (its_error) { + VSOMEIP_ERROR << "endpoint_manager_impl::create_routing_root: " + << "Remote routing root endpoint creation failed (" << its_retry << ") " + << "Client: " << std::hex << std::setw(4) << std::setfill('0') + << VSOMEIP_ROUTING_CLIENT << ": " << its_error.message(); + + its_root->deinit(); + std::this_thread::sleep_for( + std::chrono::milliseconds(VSOMEIP_ROUTING_ROOT_RECONNECT_INTERVAL)); + } + its_retry++; + } while (its_retry < VSOMEIP_ROUTING_ROOT_RECONNECT_RETRIES && its_error); + + if (its_error) { + return false; + } + + _root = its_root; + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << __func__ << ": " << e.what(); + } + + _is_socket_activated = false; + } + + return true; +} + +instance_t endpoint_manager_impl::find_instance( + service_t _service, endpoint* const _endpoint) const { + instance_t its_instance(0xFFFF); + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_service = service_instances_.find(_service); + if (found_service != service_instances_.end()) { + auto found_endpoint = found_service->second.find(_endpoint); + if (found_endpoint != found_service->second.end()) { + its_instance = found_endpoint->second; + } + } + return its_instance; +} + +instance_t endpoint_manager_impl::find_instance_multicast( + service_t _service, const boost::asio::ip::address &_sender) const { + instance_t its_instance(0xFFFF); + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_service = service_instances_multicast_.find(_service); + if (found_service != service_instances_multicast_.end()) { + auto found_sender = found_service->second.find(_sender); + if (found_sender != found_service->second.end()) { + its_instance = found_sender->second; + } + } + return its_instance; +} + +bool endpoint_manager_impl::remove_instance(service_t _service, + endpoint* const _endpoint) { + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_service = service_instances_.find(_service); + if (found_service != service_instances_.end()) { + if (found_service->second.erase(_endpoint)) { + if (!found_service->second.size()) { + service_instances_.erase(found_service); + } + } + } + } + return !is_used_endpoint(_endpoint); +} + +bool endpoint_manager_impl::remove_instance_multicast(service_t _service, + instance_t _instance) { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + auto found_service = service_instances_multicast_.find(_service); + if (found_service != service_instances_multicast_.end()) { + for (auto &its_sender : found_service->second) { + if (its_sender.second == _instance) { + if (found_service->second.erase(its_sender.first)) { + if (!found_service->second.size()) { + service_instances_multicast_.erase(_service); + } + } + return true; + } + } + } + return false; +} + +void endpoint_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) { + // Is called when endpoint->connect succeeded! + struct service_info { + service_t service_id_; + instance_t instance_id_; + major_version_t major_; + minor_version_t minor_; + std::shared_ptr<endpoint> endpoint_; + bool service_is_unreliable_only_; + }; + + // Set to state CONNECTED as connection is not yet fully established in remote side POV + // but endpoint is ready to send / receive. Set to ESTABLISHED after timer expires + // to prevent inserting subscriptions twice or send out subscription before remote side + // is finished with TCP 3 way handshake + _endpoint->set_connected(true); + + std::forward_list<struct service_info> services_to_report_; + { + const bool endpoint_is_reliable = _endpoint->is_reliable(); + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + for (auto &its_service : remote_services_) { + for (auto &its_instance : its_service.second) { + auto found_endpoint = its_instance.second.find(endpoint_is_reliable); + if (found_endpoint != its_instance.second.end()) { + if (found_endpoint->second == _endpoint) { + std::shared_ptr<serviceinfo> its_info( + rm_->find_service(its_service.first, + its_instance.first)); + if (!its_info) { + _endpoint->set_established(true); + return; + } + // only report services offered via TCP+UDP when both + // endpoints are connected + const auto its_other_endpoint = its_info->get_endpoint( + !endpoint_is_reliable); + + if (!its_other_endpoint || (its_other_endpoint + && its_other_endpoint->is_established_or_connected())) { + services_to_report_.push_front( + { its_service.first, + its_instance.first, + its_info->get_major(), + its_info->get_minor(), + _endpoint, + (!endpoint_is_reliable && + !its_other_endpoint)}); + } + } + } + } + } + } + for (const auto &s : services_to_report_) { + static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected( + s.service_id_, s.instance_id_, s.major_, s.minor_, s.endpoint_, + s.service_is_unreliable_only_); + } + if (services_to_report_.empty()) { + _endpoint->set_established(true); + } +} + +void endpoint_manager_impl::on_disconnect(std::shared_ptr<endpoint> _endpoint) { + // Is called when endpoint->connect fails! + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + for (auto &its_service : remote_services_) { + for (auto &its_instance : its_service.second) { + const bool is_reliable = _endpoint->is_reliable(); + auto found_endpoint = its_instance.second.find(is_reliable); + if (found_endpoint != its_instance.second.end()) { + if (found_endpoint->second == _endpoint) { + std::shared_ptr<serviceinfo> its_info( + rm_->find_service(its_service.first, + its_instance.first)); + if(!its_info){ + return; + } + if (!is_reliable) { + static_cast<routing_manager_impl*>(rm_)->on_availability( + its_service.first, its_instance.first, + availability_state_e::AS_UNAVAILABLE, + its_info->get_major(), its_info->get_minor()); + } + static_cast<routing_manager_impl*>(rm_)->service_endpoint_disconnected( + its_service.first, its_instance.first, + its_info->get_major(), + its_info->get_minor(), _endpoint); + } + } + } + } +} + +bool endpoint_manager_impl::on_bind_error(std::shared_ptr<endpoint> _endpoint, + const boost::asio::ip::address &_remote_address, std::uint16_t _remote_port) { + + std::lock_guard<std::recursive_mutex> its_ep_lock(endpoint_mutex_); + for (auto &its_service : remote_services_) { + for (auto &its_instance : its_service.second) { + const bool is_reliable = _endpoint->is_reliable(); + auto found_endpoint = its_instance.second.find(is_reliable); + if (found_endpoint != its_instance.second.end()) { + if (found_endpoint->second == _endpoint) { + // get a new client port using service / instance / remote port + uint16_t its_old_local_port = _endpoint->get_local_port(); + uint16_t its_new_local_port(ILLEGAL_PORT); + + std::unique_lock<std::mutex> its_lock(used_client_ports_mutex_); + std::map<bool, std::set<port_t> > its_used_client_ports; + get_used_client_ports(_remote_address, _remote_port, its_used_client_ports); + if (configuration_->get_client_port( + its_service.first, its_instance.first, + _remote_port, is_reliable, + its_used_client_ports, its_new_local_port)) { + _endpoint->set_local_port(its_new_local_port); + its_lock.unlock(); + release_used_client_port(_remote_address, _remote_port, + _endpoint->is_reliable(), its_old_local_port); + return true; + } + } + } + } + } + return false; +} + +void endpoint_manager_impl::on_error( + const byte_t *_data, length_t _length, endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + instance_t its_instance = 0; + if (_length >= VSOMEIP_SERVICE_POS_MAX) { + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + its_instance = find_instance(its_service, _receiver); + } + static_cast<routing_manager_impl*>(rm_)->send_error( + return_code_e::E_MALFORMED_MESSAGE, _data, _length, its_instance, + _receiver->is_reliable(), _receiver, _remote_address, _remote_port); +} + +void +endpoint_manager_impl::get_used_client_ports( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + std::map<bool, std::set<port_t> > &_used_ports) { + auto find_address = used_client_ports_.find(_remote_address); + if (find_address != used_client_ports_.end()) { + auto find_port = find_address->second.find(_remote_port); + if (find_port != find_address->second.end()) + _used_ports = find_port->second; + } +} + +void +endpoint_manager_impl::request_used_client_port( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + bool _reliable, port_t _local_port) { + + std::lock_guard<std::mutex> its_lock(used_client_ports_mutex_); + used_client_ports_[_remote_address][_remote_port] + [_reliable].insert(_local_port); +} + +void +endpoint_manager_impl::release_used_client_port( + const boost::asio::ip::address &_remote_address, port_t _remote_port, + bool _reliable, port_t _local_port) { + + std::lock_guard<std::mutex> its_lock(used_client_ports_mutex_); + auto find_address = used_client_ports_.find(_remote_address); + if (find_address != used_client_ports_.end()) { + auto find_port = find_address->second.find(_remote_port); + if (find_port != find_address->second.end()) { + auto find_reliable = find_port->second.find(_reliable); + if (find_reliable != find_port->second.end()) + find_reliable->second.erase(_local_port); + } + } +} + +std::shared_ptr<endpoint> +endpoint_manager_impl::find_remote_client( + service_t _service, instance_t _instance, bool _reliable) { + + std::shared_ptr<endpoint> its_endpoint; + auto found_service = remote_services_.find(_service); + if (found_service != remote_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_reliability = found_instance->second.find(_reliable); + if (found_reliability != found_instance->second.end()) { + its_endpoint = found_reliability->second; + } + } + } + if (its_endpoint) { + return its_endpoint; + } + + // Endpoint did not yet exist. Get the partition id to check + // whether the client endpoint for the partition does exist. + partition_id_t its_partition_id + = configuration_->get_partition_id(_service, _instance); + + // If another service within the same partition is hosted on the + // same server_endpoint reuse the existing client_endpoint. + auto found_service_info = remote_service_info_.find(_service); + if (found_service_info != remote_service_info_.end()) { + auto found_instance = found_service_info->second.find(_instance); + if (found_instance != found_service_info->second.end()) { + auto found_reliable = found_instance->second.find(_reliable); + if (found_reliable != found_instance->second.end()) { + std::shared_ptr<endpoint_definition> its_ep_def + = found_reliable->second; + auto found_address = client_endpoints_.find( + its_ep_def->get_address()); + if (found_address != client_endpoints_.end()) { + auto found_port = found_address->second.find( + its_ep_def->get_remote_port()); + if (found_port != found_address->second.end()) { + auto found_reliable2 + = found_port->second.find(_reliable); + if (found_reliable2 != found_port->second.end()) { + auto found_partition + = found_reliable2->second.find(its_partition_id); + if (found_partition != found_reliable2->second.end()) { + its_endpoint = found_partition->second; + + // store the endpoint under this service/instance id + // as well - needed for later cleanup + remote_services_[_service][_instance][_reliable] + = its_endpoint; + service_instances_[_service][its_endpoint.get()] = _instance; + + // add endpoint to serviceinfo object + auto found_service_info = rm_->find_service(_service,_instance); + if (found_service_info) { + found_service_info->set_endpoint(its_endpoint, _reliable); + } + } + } + } + } + } + } + } + + return its_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_impl::create_remote_client( + service_t _service, instance_t _instance, bool _reliable) { + std::shared_ptr<endpoint> its_endpoint; + std::shared_ptr<endpoint_definition> its_endpoint_def; + uint16_t its_local_port; + + boost::asio::ip::address its_remote_address; + uint16_t its_remote_port = ILLEGAL_PORT; + + auto found_service = remote_service_info_.find(_service); + if (found_service != remote_service_info_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_reliability = found_instance->second.find(_reliable); + if (found_reliability != found_instance->second.end()) { + its_endpoint_def = found_reliability->second; + its_remote_address = its_endpoint_def->get_address(); + its_remote_port = its_endpoint_def->get_port(); + } + } + } + + if( its_remote_port != ILLEGAL_PORT) { + // if client port range for remote service port range is configured + // and remote port is in range, determine unused client port + std::map<bool, std::set<port_t> > its_used_client_ports; + { + std::lock_guard<std::mutex> its_lock(used_client_ports_mutex_); + get_used_client_ports(its_remote_address, its_remote_port, its_used_client_ports); + } + if (configuration_->get_client_port(_service, _instance, + its_remote_port, _reliable, + its_used_client_ports, its_local_port)) { + if (its_endpoint_def) { + its_endpoint = create_client_endpoint( + its_remote_address, + its_local_port, + its_remote_port, + _reliable); + } + + if (its_endpoint) { + request_used_client_port(its_remote_address, its_remote_port, + _reliable, its_local_port); + + service_instances_[_service][its_endpoint.get()] = _instance; + remote_services_[_service][_instance][_reliable] = its_endpoint; + + partition_id_t its_partition + = configuration_->get_partition_id(_service, _instance); + client_endpoints_[its_endpoint_def->get_address()] + [its_endpoint_def->get_port()] + [_reliable] + [its_partition]= its_endpoint; + // Set the basic route to the service in the service info + auto found_service_info = rm_->find_service(_service, _instance); + if (found_service_info) { + found_service_info->set_endpoint(its_endpoint, _reliable); + } + boost::system::error_code ec; + VSOMEIP_INFO << "endpoint_manager_impl::create_remote_client: " + << its_endpoint_def->get_address().to_string(ec) + << ":" << std::dec << its_endpoint_def->get_port() + << " reliable: " << _reliable + << " using local port: " << std::dec << its_local_port; + } + } + } + return its_endpoint; +} + +std::shared_ptr<endpoint> endpoint_manager_impl::create_client_endpoint( + const boost::asio::ip::address &_address, + uint16_t _local_port, uint16_t _remote_port, + bool _reliable) { + + std::shared_ptr<endpoint> its_endpoint; + boost::asio::ip::address its_unicast = configuration_->get_unicast_address(); + + try { + if (_reliable) { + its_endpoint = std::make_shared<tcp_client_endpoint_impl>( + shared_from_this(), + rm_->shared_from_this(), + boost::asio::ip::tcp::endpoint(its_unicast, _local_port), + boost::asio::ip::tcp::endpoint(_address, _remote_port), + io_, + configuration_); + + if (configuration_->has_enabled_magic_cookies(_address.to_string(), + _remote_port)) { + its_endpoint->enable_magic_cookies(); + } + } else { + its_endpoint = std::make_shared<udp_client_endpoint_impl>( + shared_from_this(), + rm_->shared_from_this(), + boost::asio::ip::udp::endpoint(its_unicast, _local_port), + boost::asio::ip::udp::endpoint(_address, _remote_port), + io_, + configuration_); + } + } catch (...) { + VSOMEIP_ERROR << __func__ << " Client endpoint creation failed"; + } + + return its_endpoint; +} + +void +endpoint_manager_impl::log_client_states() const { + std::stringstream its_log; + client_endpoints_t its_client_endpoints; + std::vector< + std::pair< + std::tuple<boost::asio::ip::address, uint16_t, bool>, + size_t + > + > its_client_queue_sizes; + + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + its_client_endpoints = client_endpoints_; + } + + for (const auto &its_address : its_client_endpoints) { + for (const auto &its_port : its_address.second) { + for (const auto &its_reliability : its_port.second) { + for (const auto &its_partition : its_reliability.second) { + size_t its_queue_size = its_partition.second->get_queue_size(); + if (its_queue_size > VSOMEIP_DEFAULT_QUEUE_WARN_SIZE) + its_client_queue_sizes.push_back( + std::make_pair( + std::make_tuple( + its_address.first, + its_port.first, + its_reliability.first), + its_queue_size)); + } + } + } + } + + std::sort(its_client_queue_sizes.begin(), its_client_queue_sizes.end(), + [](const std::pair< + std::tuple<boost::asio::ip::address, uint16_t, bool>, + size_t> &_a, + const std::pair< + std::tuple<boost::asio::ip::address, uint16_t, bool>, + size_t> &_b) { + return (_a.second > _b.second); + }); + + size_t its_max(std::min(size_t(5), its_client_queue_sizes.size())); + for (size_t i = 0; i < its_max; i++) { + its_log << std::hex << std::setw(4) << std::setfill('0') + << std::get<0>(its_client_queue_sizes[i].first).to_string() + << ":" << std::dec << std::get<1>(its_client_queue_sizes[i].first) + << "(" << (std::get<2>(its_client_queue_sizes[i].first) ? "tcp" : "udp") << "):" + << std::dec << its_client_queue_sizes[i].second; + if (i < its_max-1) + its_log << ", "; + } + + if (its_log.str().length() > 0) + VSOMEIP_INFO << "ECQ: [" << its_log.str() << "]"; +} + +void +endpoint_manager_impl::log_server_states() const { + std::stringstream its_log; + server_endpoints_t its_server_endpoints; + std::vector< + std::pair< + std::pair<uint16_t, bool>, + size_t + > + > its_client_queue_sizes; + + { + std::scoped_lock its_lock {endpoint_mutex_}; + its_server_endpoints = server_endpoints_; + } + + for (const auto &its_port : its_server_endpoints) { + for (const auto &its_reliability : its_port.second) { + size_t its_queue_size = its_reliability.second->get_queue_size(); + if (its_queue_size > VSOMEIP_DEFAULT_QUEUE_WARN_SIZE) + its_client_queue_sizes.push_back( + std::make_pair( + std::make_pair( + its_port.first, + its_reliability.first), + its_queue_size)); + } + } + + std::sort(its_client_queue_sizes.begin(), its_client_queue_sizes.end(), + [](const std::pair<std::pair<uint16_t, bool>, size_t> &_a, + const std::pair<std::pair<uint16_t, bool>, size_t> &_b) { + return (_a.second > _b.second); + }); + + size_t its_max(std::min(size_t(5), its_client_queue_sizes.size())); + for (size_t i = 0; i < its_max; i++) { + its_log << std::dec << its_client_queue_sizes[i].first.first + << "(" << (its_client_queue_sizes[i].first.second ? "tcp" : "udp") << "):" + << std::dec << its_client_queue_sizes[i].second; + if (i < its_max-1) + its_log << ", "; + } + + if (its_log.str().length() > 0) + VSOMEIP_INFO << "ESQ: [" << its_log.str() << "]"; +} + +void +endpoint_manager_impl::add_multicast_option(const multicast_option_t &_option) { + + std::lock_guard<std::mutex> its_guard(options_mutex_); + options_queue_.push(_option); + options_condition_.notify_one(); +} + +void +endpoint_manager_impl::process_multicast_options() { + + std::unique_lock<std::mutex> its_lock(options_mutex_); + while (is_processing_options_) { + if (options_queue_.size() > 0) { + auto its_front = options_queue_.front(); + options_queue_.pop(); + auto its_udp_server_endpoint = + std::dynamic_pointer_cast<udp_server_endpoint_impl>(its_front.endpoint_); + if (its_udp_server_endpoint) { + // Unlock before setting the option as this might block + its_lock.unlock(); + + boost::system::error_code its_error; + its_udp_server_endpoint->set_multicast_option( + its_front.address_, its_front.is_join_, its_error); + + if (its_error) { + VSOMEIP_ERROR << __func__ << ": " + << (its_front.is_join_ ? "joining " : "leaving ") + << its_front.address_ << " (" << its_error.message() << ")"; + } + + // Lock again after setting the option + its_lock.lock(); + } + } else { + options_condition_.wait(its_lock); + } + } +} + +bool endpoint_manager_impl::is_used_endpoint(endpoint* const _endpoint) const { + + { + std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_); + // Do we still use the endpoint to offer a service instance? + for (const auto& si : service_instances_) + if (si.second.find(_endpoint) != si.second.end()) + return true; + } + + // Do we still use the endpoint to join a multicast address= + auto its_udp_server_endpoint = dynamic_cast<udp_server_endpoint_impl*>(_endpoint); + if (its_udp_server_endpoint) + return its_udp_server_endpoint->is_joining(); + + return false; +} + +void endpoint_manager_impl::suspend(void) { + + client_endpoints_t its_client_endpoints; + server_endpoints_t its_server_endpoints; + { + // TODO: Check whether we can avoid copying + std::scoped_lock its_lock {endpoint_mutex_}; + its_client_endpoints = client_endpoints_; + its_server_endpoints = server_endpoints_; + } + + // stop client endpoints + for (auto& its_address : its_client_endpoints) { + for (auto& its_port : its_address.second) { + for (auto& its_protocol : its_port.second) { + for (auto& its_partition : its_protocol.second) { + its_partition.second->stop(); + } + } + } + } + + // start server endpoints + for (auto& its_port : its_server_endpoints) { + for (auto& its_protocol : its_port.second) { + its_protocol.second->stop(); + } + } +} + +void endpoint_manager_impl::resume(void) { + client_endpoints_t its_client_endpoints; + server_endpoints_t its_server_endpoints; + { + // TODO: Check whether we can avoid copying + std::scoped_lock its_lock {endpoint_mutex_}; + its_client_endpoints = client_endpoints_; + its_server_endpoints = server_endpoints_; + } + + // start server endpoints + for (auto& its_port : its_server_endpoints) { + for (auto& its_protocol : its_port.second) { + its_protocol.second->restart(); + } + } + + // start client endpoints + for (auto& its_address : its_client_endpoints) { + for (auto& its_port : its_address.second) { + for (auto& its_protocol : its_port.second) { + for (auto& its_partition : its_protocol.second) { + its_partition.second->restart(); + } + } + } + } +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_client_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_client_endpoint_impl.cpp new file mode 100644 index 00000000000..b4f00dc553c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_client_endpoint_impl.cpp @@ -0,0 +1,417 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <iomanip> +#include <sstream> + +#include <boost/asio/write.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_host.hpp" +#include "../include/local_tcp_client_endpoint_impl.hpp" +#include "../include/local_tcp_server_endpoint_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../routing/include/routing_host.hpp" + +namespace vsomeip_v3 { + +local_tcp_client_endpoint_impl::local_tcp_client_endpoint_impl( + const std::shared_ptr<endpoint_host> &_endpoint_host, + const std::shared_ptr<routing_host> &_routing_host, + const endpoint_type & _local, + const endpoint_type &_remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration> &_configuration) + : local_tcp_client_endpoint_base_impl(_endpoint_host, _routing_host, _local, _remote, _io, + _configuration), + recv_buffer_(VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE, 0) { + + is_supporting_magic_cookies_ = false; + + this->max_message_size_ = _configuration->get_max_message_size_local(); + this->queue_limit_ = _configuration->get_endpoint_queue_limit_local(); +} + +bool local_tcp_client_endpoint_impl::is_local() const { + return true; +} + +void local_tcp_client_endpoint_impl::restart(bool _force) { + + if (!_force && state_ == cei_state_e::CONNECTING) { + return; + } + state_ = cei_state_e::CONNECTING; + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = false; + queue_.clear(); + queue_size_ = 0; + } + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + shutdown_and_close_socket_unlocked(true); + } + was_not_connected_ = true; + reconnect_counter_ = 0; + start_connect_timer(); +} + +void local_tcp_client_endpoint_impl::start() { + if (state_ == cei_state_e::CLOSED) { + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = false; + } + connect(); + } +} + +void local_tcp_client_endpoint_impl::stop() { + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = true; + } + { + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + boost::system::error_code ec; + connect_timer_.cancel(ec); + } + connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; + + bool is_open(false); + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + is_open = socket_->is_open(); + } + if (is_open) { + bool send_queue_empty(false); + std::uint32_t times_slept(0); + + while (times_slept <= 50) { + mutex_.lock(); + send_queue_empty = (queue_.size() == 0); + mutex_.unlock(); + if (send_queue_empty) { + break; + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + times_slept++; + } + } + } + shutdown_and_close_socket(false); +} + +void local_tcp_client_endpoint_impl::connect() { + boost::system::error_code its_connect_error; + std::unique_lock<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + socket_->open(remote_.protocol(), its_error); + if (!its_error || its_error == boost::asio::error::already_open) { + // Nagle algorithm off + socket_->set_option(boost::asio::ip::tcp::no_delay(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltcei::connect: couldn't disable " + << "Nagle algorithm: " << its_error.message() + << " remote:" << remote_.port() + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + } + socket_->set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltcei::connect: couldn't enable " + << "keep_alive: " << its_error.message() + << " remote:" << remote_.port() + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + } + // Setting the TIME_WAIT to 0 seconds forces RST to always be sent in reponse to a FIN + // Since this is endpoint for internal communication, setting the TIME_WAIT to 5 seconds + // should be enough to ensure the ACK to the FIN arrives to the server endpoint. + socket_->set_option(boost::asio::socket_base::linger(true, 5), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltcei::connect: couldn't enable " + << "SO_LINGER: " << its_error.message() + << " remote:" << remote_.port() + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + } + socket_->set_option(boost::asio::socket_base::reuse_address(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltcei::" << __func__ + << ": Cannot enable SO_REUSEADDR" << "(" << its_error.message() << ")" + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + } + socket_->bind(local_, its_error); + if (its_error) { + VSOMEIP_WARNING << "ltcei::" << __func__ + << ": Cannot bind to client port " << local_.port() << "(" + << its_error.message() << ")" + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + try { + strand_.post( + std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(), + its_connect_error)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "ltcei::connect: " << e.what() + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + } + return; + } + state_ = cei_state_e::CONNECTING; + start_connecting_timer(); + socket_->async_connect( + remote_, + strand_.wrap( + std::bind( + &local_tcp_client_endpoint_impl::cancel_and_connect_cbk, + shared_from_this(), + std::placeholders::_1 + ) + ) + ); + } else { + VSOMEIP_WARNING << "ltcei::connect: Error opening socket: " + << its_error.message() << " (" << std::dec << its_error.value() << ")" + << " endpoint > " << this; + its_connect_error = its_error; + try { + strand_.post( + std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(), + its_connect_error)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "ltcei::connect: " << e.what() + << " endpoint > " << this; + } + } +} + +void local_tcp_client_endpoint_impl::receive() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + socket_->async_receive( + boost::asio::buffer(recv_buffer_), + strand_.wrap( + std::bind( + &local_tcp_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< + local_tcp_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2 + ) + ) + ); + } +} + +// this overrides client_endpoint_impl::send to disable the pull method +// for local communication +bool local_tcp_client_endpoint_impl::send(const uint8_t *_data, uint32_t _size) { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + bool ret(true); + if (endpoint_impl::sending_blocked_ || + check_message_size(nullptr, _size) != cms_ret_e::MSG_OK || + !check_packetizer_space(_size) || + !check_queue_limit(_data, _size)) { + ret = false; + } else { +#if 0 + std::stringstream msg; + msg << "lce::send: "; + for (uint32_t i = 0; i < _size; i++) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + train_->buffer_->insert(train_->buffer_->end(), _data, _data + _size); + queue_train(train_); + train_->buffer_ = std::make_shared<message_buffer_t>(); + } + return ret; +} + +void local_tcp_client_endpoint_impl::send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry) { + + static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 }; + static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 }; + std::vector<boost::asio::const_buffer> bufs; + + bufs.push_back(boost::asio::buffer(its_start_tag)); + bufs.push_back(boost::asio::buffer(*_entry.first)); + bufs.push_back(boost::asio::buffer(its_end_tag)); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::asio::async_write( + *socket_, + bufs, + std::bind( + &client_endpoint_impl::send_cbk, + std::dynamic_pointer_cast< + local_tcp_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + _entry.first + ) + ); + } +} + +void local_tcp_client_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + + (void)_service; + (void)_method; + (void)_debouncing; + (void)_maximum_retention; + VSOMEIP_ERROR << "ltcei::get_configured_times_from_endpoint called." << " endpoint > " << this; +} + +void local_tcp_client_endpoint_impl::send_magic_cookie() { + +} + +void local_tcp_client_endpoint_impl::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes) { + + if (_error) { + VSOMEIP_INFO << "ltcei::" << __func__ << " Error: " << _error.message() + << " endpoint > " << this << " state_ > " << static_cast<int>(state_.load()); + if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + return; + } else if (_error == boost::asio::error::eof) { + std::scoped_lock its_lock {mutex_}; + sending_blocked_ = false; + queue_.clear(); + queue_size_ = 0; + } else if (_error == boost::asio::error::connection_reset + || _error == boost::asio::error::bad_descriptor) { + restart(true); + return; + } + error_handler_t handler; + { + std::lock_guard<std::mutex> its_lock(error_handler_mutex_); + handler = error_handler_; + } + if (handler) + handler(); + } else { + +#if 0 + std::stringstream msg; + msg << "lce<" << this << ">::recv: "; + for (std::size_t i = 0; i < recv_buffer_.size(); i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)recv_buffer_[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + // We only handle a single message here. Check whether the message + // format matches what we do expect. + // TODO: Replace the magic numbers. + if (_bytes == VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE + && recv_buffer_[0] == 0x67 && recv_buffer_[1] == 0x37 + && recv_buffer_[2] == 0x6d && recv_buffer_[3] == 0x07 + && recv_buffer_[4] == byte_t(protocol::id_e::ASSIGN_CLIENT_ACK_ID) + && recv_buffer_[15] == 0x07 && recv_buffer_[16] == 0x6d + && recv_buffer_[17] == 0x37 && recv_buffer_[18] == 0x67) { + + auto its_routing_host = routing_host_.lock(); + if (its_routing_host) + its_routing_host->on_message(&recv_buffer_[4], + static_cast<length_t>(recv_buffer_.size() - 8), this); + } + + receive(); + } +} + +std::uint16_t local_tcp_client_endpoint_impl::get_local_port() const { + + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + boost::system::error_code its_error; + endpoint_type its_local = socket_->local_endpoint(its_error); + if (!its_error) + return its_local.port(); + } + + return local_.port(); +} + +void local_tcp_client_endpoint_impl::set_local_port() { + // local_port_ is set to zero in ctor of client_endpoint_impl -> do nothing +} + +void local_tcp_client_endpoint_impl::print_status() { + + std::string its_path(""); + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + its_queue_size = queue_.size(); + its_data_size = queue_size_; + } + + VSOMEIP_INFO << "status lce: " << its_path << " queue: " + << its_queue_size << " data: " << its_data_size; +} + +std::string local_tcp_client_endpoint_impl::get_remote_information() const { + + boost::system::error_code ec; + return remote_.address().to_string(ec) + ":" + + std::to_string(remote_.port()); +} + + +bool local_tcp_client_endpoint_impl::check_packetizer_space(std::uint32_t _size) { + if (train_->buffer_->size() + _size < train_->buffer_->size()) { + VSOMEIP_ERROR << "ltcei: Overflow in packetizer addition ~> abort sending!" + << " endpoint > " << this; + return false; + } + if (train_->buffer_->size() + _size > max_message_size_ + && !train_->buffer_->empty()) { + queue_.push_back(std::make_pair(train_->buffer_, 0)); + queue_size_ += train_->buffer_->size(); + train_->buffer_ = std::make_shared<message_buffer_t>(); + } + return true; +} + +bool local_tcp_client_endpoint_impl::is_reliable() const { + + return true; +} + +std::uint32_t local_tcp_client_endpoint_impl::get_max_allowed_reconnects() const { + + return MAX_RECONNECTS_UNLIMITED; +} + +void local_tcp_client_endpoint_impl::max_allowed_reconnects_reached() { + + VSOMEIP_ERROR << "ltcei::max_allowed_reconnects_reached: " + << get_remote_information() + << " endpoint > " << this; + error_handler_t handler; + { + std::lock_guard<std::mutex> its_lock(error_handler_mutex_); + handler = error_handler_; + } + if (handler) + handler(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_server_endpoint_impl.cpp new file mode 100644 index 00000000000..3f0ce28d899 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_tcp_server_endpoint_impl.cpp @@ -0,0 +1,936 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <deque> +#include <iomanip> +#include <sstream> + +#include <sys/types.h> +#include <boost/asio/write.hpp> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_host.hpp" +#include "../include/local_tcp_server_endpoint_impl.hpp" +#include "../include/local_server_endpoint_impl_receive_op.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../protocol/include/assign_client_command.hpp" +#include "../../protocol/include/assign_client_ack_command.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +local_tcp_server_endpoint_impl::local_tcp_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint) + : local_tcp_server_endpoint_base_impl(_endpoint_host, _routing_host, _io, _configuration), + acceptor_(_io), + buffer_shrink_threshold_(_configuration->get_buffer_shrink_threshold()), + is_routing_endpoint_(_is_routing_endpoint) { + is_supporting_magic_cookies_ = false; + + this->max_message_size_ = _configuration->get_max_message_size_local(); + this->queue_limit_ = _configuration->get_endpoint_queue_limit_local(); +} +bool local_tcp_server_endpoint_impl::is_local() const { + + return true; +} + +void local_tcp_server_endpoint_impl::init(const endpoint_type& _local, + boost::system::error_code& _error) { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + init_unlocked(_local, _error); +} + +void local_tcp_server_endpoint_impl::init_unlocked(const endpoint_type& _local, + boost::system::error_code& _error) { + acceptor_.open(_local.protocol(), _error); + if (_error) + return; + +#ifndef _WIN32 + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), _error); + if (_error) + return; +#endif + + acceptor_.bind(_local, _error); + if (_error) + return; + + acceptor_.listen(boost::asio::socket_base::max_connections, _error); + if (_error) + return; + + local_ = _local; + local_port_ = _local.port(); +} + +void local_tcp_server_endpoint_impl::deinit() { + boost::system::error_code its_error; + acceptor_.close(its_error); +} + +void local_tcp_server_endpoint_impl::start() { + + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (!acceptor_.is_open()) { + boost::system::error_code its_error; + init_unlocked(local_, its_error); + } + + if (acceptor_.is_open()) { + connection::ptr new_connection = connection::create( + std::dynamic_pointer_cast<local_tcp_server_endpoint_impl>( + shared_from_this()), max_message_size_, + buffer_shrink_threshold_, + io_); + + { + std::unique_lock<std::mutex> its_lock(new_connection->get_socket_lock()); + acceptor_.async_accept( + new_connection->get_socket(), + std::bind( + &local_tcp_server_endpoint_impl::accept_cbk, + std::dynamic_pointer_cast< + local_tcp_server_endpoint_impl + >(shared_from_this()), + new_connection, + std::placeholders::_1 + ) + ); + } + } +} + +void local_tcp_server_endpoint_impl::stop() { + + server_endpoint_impl::stop(); + { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } + } + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (const auto &c : connections_) { + c.second->stop(); + } + connections_.clear(); + } +} + +bool local_tcp_server_endpoint_impl::send(const uint8_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "lse(" << get_local_port() << ")::send "; + for (uint32_t i = 0; i < _size; i++) + msg << std::setw(2) << std::setfill('0') << std::hex << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::lock_guard<std::mutex> its_lock(mutex_); + if (endpoint_impl::sending_blocked_) { + return false; + } + + client_t its_client; + std::memcpy(&its_client, &_data[protocol::COMMAND_HEADER_SIZE], sizeof(its_client)); + + connection::ptr its_connection; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + const auto its_iterator = connections_.find(its_client); + if (its_iterator == connections_.end()) { + return false; + } else { + its_connection = its_iterator->second; + } + } + + auto its_buffer = std::make_shared<message_buffer_t>(); + its_buffer->insert(its_buffer->end(), _data, _data + _size); + its_connection->send_queued(its_buffer); + + return true; +} + +bool local_tcp_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_tcp_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_tcp_server_endpoint_impl::send_queued( + const target_data_iterator_type _it) { + + (void)_it; + + return false; +} + +void local_tcp_server_endpoint_impl::receive() { + + // intentionally left empty +} + +bool local_tcp_server_endpoint_impl::get_default_target( + service_t, + local_tcp_server_endpoint_impl::endpoint_type &) const { + + return false; +} + +bool local_tcp_server_endpoint_impl::add_connection(const client_t &_client, + const std::shared_ptr<connection> &_connection) { + + bool ret = false; + std::lock_guard<std::mutex> its_lock(connections_mutex_); + auto find_connection = connections_.find(_client); + if (find_connection == connections_.end()) { + connections_[_client] = _connection; + ret = true; + } else { + VSOMEIP_WARNING << "Attempt to add already existing " + "connection to client " << std::hex << _client << " endpoint > " << this; + } + return ret; +} + +void local_tcp_server_endpoint_impl::remove_connection( + const client_t &_client) { + + std::lock_guard<std::mutex> its_lock(connections_mutex_); + connections_.erase(_client); +} + +void local_tcp_server_endpoint_impl::accept_cbk( + const connection::ptr& _connection, boost::system::error_code const &_error) { + if (!_error) { + boost::system::error_code its_error; + endpoint_type remote; + { + std::unique_lock<std::mutex> its_socket_lock(_connection->get_socket_lock()); + socket_type &new_connection_socket = _connection->get_socket(); + + // Nagle algorithm off + new_connection_socket.set_option(boost::asio::ip::tcp::no_delay(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltsei::accept_cbk: couldn't disable " + << "Nagle algorithm: " << its_error.message() + << " endpoint > " << this; + } + new_connection_socket.set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "ltsei::accept_cbk: couldn't enable " + << "keep_alive: " << its_error.message() + << " endpoint > " << this; + } + } + } + if (_error != boost::asio::error::bad_descriptor + && _error != boost::asio::error::operation_aborted + && _error != boost::asio::error::no_descriptors) { + start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR << "ltsei::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms" + << " endpoint > " << this; + auto its_timer = + std::make_shared<boost::asio::steady_timer>(io_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<local_tcp_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error) { + if (!_error) { + its_ep->start(); + } + }); + } + if (!_error) { + _connection->start(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// class local_service_impl::connection +/////////////////////////////////////////////////////////////////////////////// + +local_tcp_server_endpoint_impl::connection::connection( + const std::shared_ptr<local_tcp_server_endpoint_impl> &_server, + std::uint32_t _max_message_size, + std::uint32_t _initial_recv_buffer_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) + : socket_(_io), + server_(_server), + recv_buffer_size_initial_(_initial_recv_buffer_size + 8), + max_message_size_(_max_message_size), + recv_buffer_(recv_buffer_size_initial_, 0), + recv_buffer_size_(0), + missing_capacity_(0), + shrink_count_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold), + bound_client_(VSOMEIP_CLIENT_UNSET), + bound_client_host_(""), + assigned_client_(false), + is_stopped_(true) { + if (_server->is_routing_endpoint_ && + !_server->configuration_->is_security_enabled()) { + assigned_client_ = true; + } + + sec_client_.host = 0; + sec_client_.port = VSOMEIP_SEC_PORT_UNSET; +} + +local_tcp_server_endpoint_impl::connection::ptr +local_tcp_server_endpoint_impl::connection::create( + const std::shared_ptr<local_tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) { + const std::uint32_t its_initial_buffer_size + = static_cast<std::uint32_t>(protocol::COMMAND_HEADER_SIZE + + sizeof(instance_t) + sizeof(bool) + sizeof(bool)); + return ptr(new connection(_server, _max_message_size, its_initial_buffer_size, + _buffer_shrink_threshold, _io)); +} + +local_tcp_server_endpoint_impl::socket_type & +local_tcp_server_endpoint_impl::connection::get_socket() { + return socket_; +} + +std::unique_lock<std::mutex> +local_tcp_server_endpoint_impl::connection::get_socket_lock() { + return std::unique_lock<std::mutex>(socket_mutex_); +} + +void local_tcp_server_endpoint_impl::connection::start() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + const std::size_t its_capacity(recv_buffer_.capacity()); + if (recv_buffer_size_ > its_capacity) { + VSOMEIP_ERROR << __func__ << "Received buffer size is greater than the buffer capacity!" + << " recv_buffer_size_: " << recv_buffer_size_ + << " its_capacity: " << its_capacity + << " endpoint > " << this; + return; + } + size_t left_buffer_size = its_capacity - recv_buffer_size_; + try { + if (missing_capacity_) { + if (missing_capacity_ > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!" + << " endpoint > " << this; + return; + } + const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_); + if (its_capacity < its_required_capacity) { + // Make the resize to its_required_capacity + recv_buffer_.reserve(its_required_capacity); + recv_buffer_.resize(its_required_capacity, 0x0); + } + left_buffer_size = missing_capacity_; + missing_capacity_ = 0; + } else if (buffer_shrink_threshold_ + && shrink_count_ > buffer_shrink_threshold_ + && recv_buffer_size_ == 0) { + // In this case, make the resize to recv_buffer_size_initial_ + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + // And set buffer_size to recv_buffer_size_initial_, the same of our resize + left_buffer_size = recv_buffer_size_initial_; + shrink_count_ = 0; + } + } catch (const std::exception &e) { + handle_recv_buffer_exception(e); + // don't start receiving again + return; + } + + is_stopped_ = false; + socket_.async_receive( + boost::asio::buffer(&recv_buffer_[recv_buffer_size_], left_buffer_size), + std::bind( + &local_tcp_server_endpoint_impl::connection::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +void local_tcp_server_endpoint_impl::connection::stop() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + is_stopped_ = true; + if (socket_.is_open()) { +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "ltsei: socket/handle closed already '" + << std::string(std::strerror(errno)) << "' (" << errno << ") " + << get_path_local() << " endpoint > " << this; + } +#endif + boost::system::error_code its_error; + socket_.cancel(its_error); + } +} + +void local_tcp_server_endpoint_impl::connection::send_queued( + const message_buffer_ptr_t& _buffer) { + + std::shared_ptr<local_tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "ltsei::connection::send_queued " + " couldn't lock server_" << " endpoint > " << this; + return; + } + + static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 }; + static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 }; + std::vector<boost::asio::const_buffer> bufs; + +#if 0 + std::stringstream msg; + msg << "ltsei::sq: "; + for (std::size_t i = 0; i < _buffer->size(); i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)(*_buffer)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + bufs.push_back(boost::asio::buffer(its_start_tag)); + bufs.push_back(boost::asio::buffer(*_buffer)); + bufs.push_back(boost::asio::buffer(its_end_tag)); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::asio::async_write( + socket_, + bufs, + std::bind( + &local_tcp_server_endpoint_impl::connection::send_cbk, + shared_from_this(), + _buffer, + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +client_t local_tcp_server_endpoint_impl::assign_client( + const byte_t *_data, uint32_t _size) { + + std::vector<byte_t> its_data(_data, _data + _size); + + protocol::assign_client_command its_command; + protocol::error_e its_error; + + its_command.deserialize(its_data, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ + << ": assign client command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return VSOMEIP_CLIENT_UNSET; + } + + return utility::request_client_id(configuration_, + its_command.get_name(), its_command.get_client()); +} + +void local_tcp_server_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, + method_t _method, std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + (void)_service; + (void)_method; + (void)_debouncing; + (void)_maximum_retention; + VSOMEIP_ERROR << "ltsei::get_configured_times_from_endpoint." << " endpoint > " << this; +} + +void local_tcp_server_endpoint_impl::connection::send_cbk(const message_buffer_ptr_t _buffer, + boost::system::error_code const &_error, std::size_t _bytes) { + (void)_buffer; + (void)_bytes; + if (_error) + VSOMEIP_WARNING << "ltsei::send_cbk received error: " << _error.message() + << " endpoint > " << this; +} + +void local_tcp_server_endpoint_impl::connection::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes) +{ + std::shared_ptr<local_tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "ltsei::connection::receive_cbk couldn't lock server_" + << " endpoint > " << this; + return; + } + std::shared_ptr<routing_host> its_host = its_server->routing_host_.lock(); + if (!its_host) + return; + + if (_error == boost::asio::error::operation_aborted) { + if (its_server->is_routing_endpoint_ && its_server->configuration_ && + bound_client_ != VSOMEIP_CLIENT_UNSET) { + utility::release_client_id(its_server->configuration_->get_network(), + bound_client_); + set_bound_client(VSOMEIP_CLIENT_UNSET); + } + + // connection was stopped + return; + } + + bool is_error(false); + std::size_t its_start = 0; + std::size_t its_end = 0; + std::size_t its_iteration_gap = 0; + std::uint32_t its_command_size = 0; + + if (!_error && 0 < _bytes) { +#if 0 + std::stringstream msg; + msg << "lse::c<" << this << ">rcb: "; + for (std::size_t i = 0; i < _bytes + recv_buffer_size_; i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int) (recv_buffer_[i]) << " "; + VSOMEIP_INFO << msg.str(); +#endif + + if (recv_buffer_size_ + _bytes < recv_buffer_size_) { + VSOMEIP_ERROR << "receive buffer overflow in local tcp server endpoint ~> abort!" + << " endpoint > " << this; + return; + } + recv_buffer_size_ += _bytes; + + bool message_is_empty(false); + bool found_message(false); + + do { + found_message = false; + message_is_empty = false; + + its_start = 0 + its_iteration_gap; + if (its_start + 3 < its_start) { + VSOMEIP_ERROR << "buffer overflow in local tcp server endpoint ~> abort!" + << " endpoint > " << this; + return; + } + while (its_start + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_start] != 0x67 || + recv_buffer_[its_start+1] != 0x37 || + recv_buffer_[its_start+2] != 0x6d || + recv_buffer_[its_start+3] != 0x07)) { + its_start++; + } + + if (its_start + 3 == recv_buffer_size_ + its_iteration_gap) { + message_is_empty = true; + } else { + its_start += 4; + } + + if (!message_is_empty) { + if (its_start + protocol::COMMAND_POSITION_SIZE + 3 < recv_buffer_size_ + its_iteration_gap) { + its_command_size = bithelper::read_uint32_le(&recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE]); + its_end = its_start + protocol::COMMAND_POSITION_SIZE + 3 + its_command_size; + } else { + its_end = its_start; + } + if (its_command_size && max_message_size_ != MESSAGE_SIZE_UNLIMITED + && its_command_size > max_message_size_) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Received a local message which exceeds " + << "maximum message size (" << std::dec << its_command_size + << ") aborting! local: " << get_path_local() << " remote: " + << get_path_remote() + << " endpoint > " << this; + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + return; + } + if (its_end + 3 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!" + << " endpoint > " << this; + return; + } + while (its_end + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_end] != 0x07 || + recv_buffer_[its_end+1] != 0x6d || + recv_buffer_[its_end+2] != 0x37 || + recv_buffer_[its_end+3] != 0x67)) { + its_end ++; + } + if (its_end + 4 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!" + << " endpoint > " << this; + return; + } + // check if we received a full message + if (recv_buffer_size_ + its_iteration_gap < its_end + 4 + || recv_buffer_[its_end] != 0x07 + || recv_buffer_[its_end+1] != 0x6d + || recv_buffer_[its_end+2] != 0x37 + || recv_buffer_[its_end+3] != 0x67) { + // command (1 Byte) + version (2 Byte) client id (2 Byte) + // + command size (4 Byte) + data itself + stop tag (4 byte) + // = 11 Bytes not covered in command size. + // If need to change the recv_buffer_, change the value of missing_capacity_ + // in this if/else, otherwise it is 0 + if (its_start - its_iteration_gap + its_command_size + + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE > recv_buffer_size_) { + missing_capacity_ = + std::uint32_t(its_start) - std::uint32_t(its_iteration_gap) + + its_command_size + std::uint32_t(protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) + - std::uint32_t(recv_buffer_size_); + } else if (recv_buffer_size_ < protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) { + // to little data to read out the command size + // minimal amount of data needed to read out command size = 11 + missing_capacity_ = static_cast<std::uint32_t>( + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE - recv_buffer_size_); + } else { + std::stringstream local_msg; + local_msg << std::setfill('0') << std::hex; + for (std::size_t i = its_iteration_gap; + i < recv_buffer_size_ + its_iteration_gap && + i - its_iteration_gap < 32; i++) { + local_msg << std::setw(2) << (int) recv_buffer_[i] << " "; + } + VSOMEIP_ERROR << "ltsei::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << recv_buffer_size_ << " but couldn't read " + "out command size. recv_buffer_capacity: " + << std::dec << recv_buffer_.capacity() + << " its_iteration_gap: " << std::dec + << its_iteration_gap << " bound client: 0x" + << std::hex << bound_client_ << " buffer: " + << local_msg.str(); + recv_buffer_size_ = 0; + missing_capacity_ = 0; + its_iteration_gap = 0; + message_is_empty = true; + } + } + } + + if (!message_is_empty && + its_end + 3 < recv_buffer_size_ + its_iteration_gap) { + + if (its_server->is_routing_endpoint_ + && recv_buffer_[its_start] == protocol::id_e::ASSIGN_CLIENT_ID) { + client_t its_client = its_server->assign_client( + &recv_buffer_[its_start], uint32_t(its_end - its_start)); + { + set_bound_client(its_client); + its_host->add_known_client(its_client, get_bound_client_host()); + its_server->add_connection(its_client, shared_from_this()); + } + its_server->send_client_identifier(its_client); + assigned_client_ = true; + } else if (!its_server->is_routing_endpoint_ || assigned_client_) { + boost::system::error_code ec; + auto its_endpoint = socket_.remote_endpoint(ec); + if (!ec) { + auto its_address = its_endpoint.address(); + auto its_port = its_endpoint.port(); + + if (its_address.is_v4()) { + sec_client_.host + = htonl(uint32_t(its_address.to_v4().to_ulong())); + } + sec_client_.port = htons(its_port); + its_server->configuration_->get_security()->sync_client(&sec_client_); + + its_host->on_message(&recv_buffer_[its_start], + uint32_t(its_end - its_start), its_server.get(), + false, bound_client_, &sec_client_, + its_address, its_port); + } else { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " endpoint encountered an error[" << ec.value() << "]: " + << ec.message() << " endpoint > " << this; + } + } else { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " didn't receive VSOMEIP_ASSIGN_CLIENT as first message" + << " endpoint > " << this; + } + #if 0 + std::stringstream local_msg; + local_msg << "lse::c<" << this << ">rcb::thunk: "; + for (std::size_t i = its_start; i < its_end; i++) + local_msg << std::setw(2) << std::setfill('0') << std::hex + << (int) recv_buffer_[i] << " "; + VSOMEIP_INFO << local_msg.str(); + #endif + calculate_shrink_count(); + recv_buffer_size_ -= (its_end + 4 - its_iteration_gap); + missing_capacity_ = 0; + its_command_size = 0; + found_message = true; + its_iteration_gap = its_end + 4; + } else { + if (its_iteration_gap) { + // Message not complete and not in front of the buffer! + // Copy last part to front for consume in future receive_cbk call! + for (size_t i = 0; i < recv_buffer_size_; ++i) { + recv_buffer_[i] = recv_buffer_[i + its_iteration_gap]; + } + // Still more capacity needed after shifting everything to front? + if (missing_capacity_ && + missing_capacity_ <= recv_buffer_.capacity() - recv_buffer_size_) { + missing_capacity_ = 0; + } + } else if (message_is_empty) { + VSOMEIP_ERROR << "Received garbage data." << " endpoint > " << this; + is_error = true; + } + } + } while (recv_buffer_size_ > 0 && found_message); + } + + if (is_stopped_ + || _error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset + || is_error) { + shutdown_and_close(); + its_server->remove_connection(bound_client_); + its_server->configuration_->get_policy_manager()->remove_client_to_sec_client_mapping(bound_client_); + } else if (_error != boost::asio::error::bad_descriptor) { + start(); + } +} + +void local_tcp_server_endpoint_impl::connection::set_bound_client(client_t _client) { + bound_client_ = _client; +} + +client_t local_tcp_server_endpoint_impl::connection::get_bound_client() const { + return bound_client_; +} + +void local_tcp_server_endpoint_impl::connection::set_bound_client_host( + const std::string &_bound_client_host) { + bound_client_host_ = _bound_client_host; +} + +std::string local_tcp_server_endpoint_impl::connection::get_bound_client_host() const { + return bound_client_host_; +} + +void local_tcp_server_endpoint_impl::connection::calculate_shrink_count() { + if (buffer_shrink_threshold_) { + if (recv_buffer_.capacity() != recv_buffer_size_initial_) { + if (recv_buffer_size_ < (recv_buffer_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + } +} + +std::string local_tcp_server_endpoint_impl::connection::get_path_local() const { + boost::system::error_code ec; + std::string its_local_path; + if (socket_.is_open()) { + endpoint_type its_local_endpoint = socket_.local_endpoint(ec); + if (!ec) { + its_local_path += its_local_endpoint.address().to_string(ec); + its_local_path += ":"; + its_local_path += std::to_string(its_local_endpoint.port()); + } + } + return its_local_path; +} + +std::string local_tcp_server_endpoint_impl::connection::get_path_remote() const { + boost::system::error_code ec; + std::string its_remote_path; + if (socket_.is_open()) { + endpoint_type its_remote_endpoint = socket_.remote_endpoint(ec); + if (!ec) { + its_remote_path += its_remote_endpoint.address().to_string(ec); + its_remote_path += ":"; + its_remote_path += std::to_string(its_remote_endpoint.port()); + } + } + return its_remote_path; +} + +void local_tcp_server_endpoint_impl::connection::handle_recv_buffer_exception( + const std::exception &_e) { + std::stringstream its_message; + its_message << "local_tcp_server_endpoint_impl::connection catched exception" + << _e.what() << " local: " << get_path_local() << " remote: " + << get_path_remote() << " shutting down connection. Start of buffer: " + << std::setfill('0') << std::hex; + + for (std::size_t i = 0; i < recv_buffer_size_ && i < 16; i++) { + its_message << std::setw(2) << (int) (recv_buffer_[i]) << " "; + } + + its_message << " Last 16 Bytes captured: "; + for (int i = 15; recv_buffer_size_ > 15u && i >= 0; i--) { + its_message << std::setw(2) << (int) (recv_buffer_[static_cast<size_t>(i)]) << " "; + } + VSOMEIP_ERROR << its_message.str(); + recv_buffer_.clear(); + if (socket_.is_open()) { + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + } + std::shared_ptr<local_tcp_server_endpoint_impl> its_server = server_.lock(); + if (its_server) { + its_server->remove_connection(bound_client_); + } +} + +std::size_t +local_tcp_server_endpoint_impl::connection::get_recv_buffer_capacity() const { + return recv_buffer_.capacity(); +} + +void +local_tcp_server_endpoint_impl::connection::shutdown_and_close() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + shutdown_and_close_unlocked(); +} + +void +local_tcp_server_endpoint_impl::connection::shutdown_and_close_unlocked() { + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); +} + +void local_tcp_server_endpoint_impl::print_status() { + std::lock_guard<std::mutex> its_lock(mutex_); + connections_t its_connections; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + its_connections = connections_; + } + std::string its_local_path("TCP"); + VSOMEIP_INFO << "status lse: " << its_local_path << " connections: " + << std::dec << its_connections.size() << " queues: " + << std::dec << targets_.size(); + for (const auto &c : its_connections) { + std::string its_remote_path; // TODO: construct the path + + std::size_t its_recv_size(0); + { + std::unique_lock<std::mutex> c_s_lock(c.second->get_socket_lock()); + its_recv_size = c.second->get_recv_buffer_capacity(); + } + + VSOMEIP_INFO << "status lse: client: " << its_remote_path + << " recv_buffer: " << std::dec << its_recv_size; + } +} +std::string local_tcp_server_endpoint_impl::get_remote_information( + const target_data_iterator_type _it) const { + boost::system::error_code ec; + return _it->first.address().to_string(ec) + ":" + + std::to_string(_it->first.port()); +} + +std::string local_tcp_server_endpoint_impl::get_remote_information( + const endpoint_type& _remote) const { + + boost::system::error_code ec; + return _remote.address().to_string(ec) + ":" + + std::to_string(_remote.port()); +} + +bool local_tcp_server_endpoint_impl::is_reliable() const { + return false; +} + +std::uint16_t local_tcp_server_endpoint_impl::get_local_port() const { + + return local_port_; +} + +void local_tcp_server_endpoint_impl::set_local_port(std::uint16_t _port) { + + (void)_port; + // Intentionally left empty +} + +bool local_tcp_server_endpoint_impl::check_packetizer_space( + target_data_iterator_type _it, message_buffer_ptr_t* _packetizer, + std::uint32_t _size) { + + if ((*_packetizer)->size() + _size < (*_packetizer)->size()) { + VSOMEIP_ERROR << "Overflow in packetizer addition ~> abort sending!"; + return false; + } + if ((*_packetizer)->size() + _size > max_message_size_ + && !(*_packetizer)->empty()) { + _it->second.queue_.push_back(std::make_pair(*_packetizer, 0)); + _it->second.queue_size_ += (*_packetizer)->size(); + *_packetizer = std::make_shared<message_buffer_t>(); + } + return true; +} + +void +local_tcp_server_endpoint_impl::send_client_identifier( + const client_t &_client) { + + protocol::assign_client_ack_command its_command; + its_command.set_client(VSOMEIP_ROUTING_CLIENT); + its_command.set_assigned(_client); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << "ltsei::" << __func__ + << ": assign client ack command serialization failed (" + << std::dec << static_cast<int>(its_error) << ")" + << " endpoint > " << this; + return; + } + + send(&its_buffer[0], static_cast<uint32_t>(its_buffer.size())); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_client_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_client_endpoint_impl.cpp new file mode 100644 index 00000000000..deca6d8509c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_client_endpoint_impl.cpp @@ -0,0 +1,388 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <iomanip> +#include <sstream> + +#include <boost/asio/write.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifndef __QNX__ +#include "../include/credentials.hpp" +#endif +#include "../include/endpoint_host.hpp" +#include "../include/local_uds_client_endpoint_impl.hpp" +#include "../include/local_uds_server_endpoint_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../routing/include/routing_host.hpp" + +namespace vsomeip_v3 { + +local_uds_client_endpoint_impl::local_uds_client_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _remote, + boost::asio::io_context& _io, + const std::shared_ptr<configuration>& _configuration) + : local_uds_client_endpoint_base_impl(_endpoint_host, _routing_host, _remote, + _remote, _io, _configuration), + // Using _remote for the local(!) endpoint is ok, + // because we have no bind for local endpoints! + recv_buffer_(VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE, 0) { + + is_supporting_magic_cookies_ = false; + + this->max_message_size_ = _configuration->get_max_message_size_local(); + this->queue_limit_ = _configuration->get_endpoint_queue_limit_local(); +} + +bool local_uds_client_endpoint_impl::is_local() const { + return true; +} + +void local_uds_client_endpoint_impl::restart(bool _force) { + if (!_force && state_ == cei_state_e::CONNECTING) { + return; + } + state_ = cei_state_e::CONNECTING; + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = false; + queue_.clear(); + queue_size_ = 0; + } + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + shutdown_and_close_socket_unlocked(true); + } + was_not_connected_ = true; + reconnect_counter_ = 0; + start_connect_timer(); +} + +void local_uds_client_endpoint_impl::start() { + if (state_ == cei_state_e::CLOSED) { + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = false; + } + connect(); + } +} + +void local_uds_client_endpoint_impl::stop() { + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = true; + } + { + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + boost::system::error_code ec; + connect_timer_.cancel(ec); + } + connect_timeout_ = VSOMEIP_DEFAULT_CONNECT_TIMEOUT; + + bool is_open(false); + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + is_open = socket_->is_open(); + } + if (is_open) { + bool send_queue_empty(false); + std::uint32_t times_slept(0); + + while (times_slept <= 50) { + mutex_.lock(); + send_queue_empty = (queue_.size() == 0); + mutex_.unlock(); + if (send_queue_empty) { + break; + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + times_slept++; + } + } + } + shutdown_and_close_socket(false); +} + +void local_uds_client_endpoint_impl::connect() { + start_connecting_timer(); + boost::system::error_code its_connect_error; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + socket_->open(remote_.protocol(), its_error); + + if (!its_error || its_error == boost::asio::error::already_open) { + socket_->set_option(boost::asio::socket_base::reuse_address(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "local_client_endpoint_impl::connect: " + << "couldn't enable SO_REUSEADDR: " << its_error.message(); + } + state_ = cei_state_e::CONNECTING; + socket_->connect(remote_, its_connect_error); + + // Credentials + #ifndef __QNX__ + if (!its_connect_error) { + auto its_host = endpoint_host_.lock(); + if (its_host) { + credentials::send_credentials(socket_->native_handle(), + its_host->get_client(), its_host->get_client_host()); + } + } else { + VSOMEIP_WARNING << "local_client_endpoint::connect: Couldn't " + << "connect to: " << remote_.path() << " (" + << its_connect_error.message() << " / " << std::dec + << its_connect_error.value() << ")"; + } + #endif + } else { + VSOMEIP_WARNING << "local_client_endpoint::connect: Error opening socket: " + << its_error.message() << " (" << std::dec << its_error.value() + << ")"; + its_connect_error = its_error; + } + } + std::size_t operations_cancelled; + { + std::lock_guard<std::mutex> its_lock(connecting_timer_mutex_); + operations_cancelled = connecting_timer_.cancel(); + } + if (operations_cancelled != 0) { + // call connect_cbk asynchronously + try { + strand_.post( + std::bind(&client_endpoint_impl::connect_cbk, shared_from_this(), + its_connect_error)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "local_client_endpoint_impl::connect: " << e.what(); + } + } +} + +void local_uds_client_endpoint_impl::receive() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + socket_->async_receive( + boost::asio::buffer(recv_buffer_), + strand_.wrap( + std::bind( + &local_uds_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< + local_uds_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2 + ) + ) + ); + } +} + +// this overrides client_endpoint_impl::send to disable the pull method +// for local communication +bool local_uds_client_endpoint_impl::send(const uint8_t *_data, uint32_t _size) { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + bool ret(true); + if (endpoint_impl::sending_blocked_ || + check_message_size(nullptr, _size) != cms_ret_e::MSG_OK || + !check_packetizer_space(_size) || + !check_queue_limit(_data, _size)) { + ret = false; + } else { +#if 0 + std::stringstream msg; + msg << "lce::send: "; + for (uint32_t i = 0; i < _size; i++) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + train_->buffer_->insert(train_->buffer_->end(), _data, _data + _size); + queue_train(train_); + train_->buffer_ = std::make_shared<message_buffer_t>(); + } + return ret; +} + +void local_uds_client_endpoint_impl::send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry) { + + static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 }; + static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 }; + std::vector<boost::asio::const_buffer> bufs; + + bufs.push_back(boost::asio::buffer(its_start_tag)); + bufs.push_back(boost::asio::buffer(*_entry.first)); + bufs.push_back(boost::asio::buffer(its_end_tag)); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::asio::async_write( + *socket_, + bufs, + std::bind( + &client_endpoint_impl::send_cbk, + std::dynamic_pointer_cast< + local_uds_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + _entry.first + ) + ); + } +} + +void local_uds_client_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + + (void)_service; + (void)_method; + (void)_debouncing; + (void)_maximum_retention; + VSOMEIP_ERROR << "local_client_endpoint_impl::get_configured_times_from_endpoint called."; +} + +void local_uds_client_endpoint_impl::send_magic_cookie() { + +} + +void local_uds_client_endpoint_impl::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes) { + + if (_error) { + VSOMEIP_INFO << "local_uds_client_endpoint_impl::" << __func__ << " Error: " << _error.message(); + if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + return; + } else if (_error == boost::asio::error::eof) { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = false; + queue_.clear(); + queue_size_ = 0; + } else if (_error == boost::asio::error::connection_reset + || _error == boost::asio::error::bad_descriptor) { + restart(true); + return; + } + error_handler_t handler; + { + std::lock_guard<std::mutex> its_lock(error_handler_mutex_); + handler = error_handler_; + } + if (handler) + handler(); + } else { + +#if 0 + std::stringstream msg; + msg << "lce<" << this << ">::recv: "; + for (std::size_t i = 0; i < recv_buffer_.size(); i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)recv_buffer_[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + // We only handle a single message here. Check whether the message + // format matches what we do expect. + // TODO: Replace the magic numbers. + if (_bytes == VSOMEIP_LOCAL_CLIENT_ENDPOINT_RECV_BUFFER_SIZE + && recv_buffer_[0] == 0x67 && recv_buffer_[1] == 0x37 + && recv_buffer_[2] == 0x6d && recv_buffer_[3] == 0x07 + && recv_buffer_[4] == byte_t(protocol::id_e::ASSIGN_CLIENT_ACK_ID) + && recv_buffer_[15] == 0x07 && recv_buffer_[16] == 0x6d + && recv_buffer_[17] == 0x37 && recv_buffer_[18] == 0x67) { + + auto its_routing_host = routing_host_.lock(); + if (its_routing_host) + its_routing_host->on_message(&recv_buffer_[4], + static_cast<length_t>(recv_buffer_.size() - 8), this); + } + + receive(); + } +} + +bool local_uds_client_endpoint_impl::get_remote_address( + boost::asio::ip::address &_address) const { + (void)_address; + return false; +} + +std::uint16_t local_uds_client_endpoint_impl::get_remote_port() const { + return 0; +} + +void local_uds_client_endpoint_impl::set_local_port() { + // local_port_ is set to zero in ctor of client_endpoint_impl -> do nothing +} + +void local_uds_client_endpoint_impl::print_status() { + + std::string its_path = remote_.path(); + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + its_queue_size = queue_.size(); + its_data_size = queue_size_; + } + + VSOMEIP_INFO << "status lce: " << its_path << " queue: " + << its_queue_size << " data: " << its_data_size; +} + +std::string local_uds_client_endpoint_impl::get_remote_information() const { + + return remote_.path(); +} + + +bool local_uds_client_endpoint_impl::check_packetizer_space(std::uint32_t _size) { + if (train_->buffer_->size() + _size < train_->buffer_->size()) { + VSOMEIP_ERROR << "Overflow in packetizer addition ~> abort sending!"; + return false; + } + if (train_->buffer_->size() + _size > max_message_size_ + && !train_->buffer_->empty()) { + queue_.push_back(std::make_pair(train_->buffer_, 0)); + queue_size_ += train_->buffer_->size(); + train_->buffer_ = std::make_shared<message_buffer_t>(); + } + return true; +} + +bool local_uds_client_endpoint_impl::is_reliable() const { + + return false; +} + +std::uint32_t local_uds_client_endpoint_impl::get_max_allowed_reconnects() const { + + return 13; +} + +void local_uds_client_endpoint_impl::max_allowed_reconnects_reached() { + + VSOMEIP_ERROR << "local_client_endpoint::max_allowed_reconnects_reached: " + << get_remote_information(); + error_handler_t handler; + { + std::lock_guard<std::mutex> its_lock(error_handler_mutex_); + handler = error_handler_; + } + if (handler) + handler(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp new file mode 100644 index 00000000000..0b552b4559c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp @@ -0,0 +1,1046 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <deque> +#include <iomanip> +#include <sstream> + +#include <sys/types.h> +#include <boost/asio/write.hpp> + +#include <vsomeip/internal/logger.hpp> + +#ifndef __QNX__ +#include "../include/credentials.hpp" +#endif +#include "../include/endpoint_host.hpp" +#include "../include/local_uds_server_endpoint_impl.hpp" +#include "../include/local_server_endpoint_impl_receive_op.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../protocol/include/assign_client_command.hpp" +#include "../../protocol/include/assign_client_ack_command.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +local_uds_server_endpoint_impl::local_uds_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint) + : local_uds_server_endpoint_base_impl(_endpoint_host, _routing_host, _io, _configuration), + acceptor_(_io), + buffer_shrink_threshold_(_configuration->get_buffer_shrink_threshold()), + is_routing_endpoint_(_is_routing_endpoint) { + is_supporting_magic_cookies_ = false; + + this->max_message_size_ = _configuration->get_max_message_size_local(); + this->queue_limit_ = _configuration->get_endpoint_queue_limit_local(); +} + +void local_uds_server_endpoint_impl::init(const endpoint_type& _local, + boost::system::error_code& _error) { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + acceptor_.open(_local.protocol(), _error); + if (_error) + return; + + init_helper(_local, _error); +} + +void local_uds_server_endpoint_impl::init(const endpoint_type& _local, const int _socket, + boost::system::error_code& _error) { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + acceptor_.assign(_local.protocol(), _socket, _error); + if (_error) + return; + + init_helper(_local, _error); +} + +void local_uds_server_endpoint_impl::init_helper(const endpoint_type& _local, + boost::system::error_code& _error) { + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), _error); + if (_error) + return; + + acceptor_.bind(_local, _error); + if (_error) + return; + + acceptor_.listen(boost::asio::socket_base::max_connections, _error); + if (_error) + return; + +#ifndef __QNX__ + if (chmod(_local.path().c_str(), + static_cast<mode_t>(configuration_->get_permissions_uds())) == -1) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } + credentials::activate_credentials(acceptor_.native_handle()); +#endif + + local_ = _local; + +} + +void local_uds_server_endpoint_impl::deinit() { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + boost::system::error_code its_error; + acceptor_.close(its_error); +} + +void local_uds_server_endpoint_impl::start() { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + connection::ptr new_connection = connection::create( + std::dynamic_pointer_cast<local_uds_server_endpoint_impl>( + shared_from_this()), max_message_size_, + buffer_shrink_threshold_, + io_); + + { + std::unique_lock<std::mutex> its_lock(new_connection->get_socket_lock()); + acceptor_.async_accept( + new_connection->get_socket(), + std::bind( + &local_uds_server_endpoint_impl::accept_cbk, + std::dynamic_pointer_cast< + local_uds_server_endpoint_impl + >(shared_from_this()), + new_connection, + std::placeholders::_1 + ) + ); + } + } +} + +void local_uds_server_endpoint_impl::stop() { + + server_endpoint_impl::stop(); + { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } + } + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (const auto &c : connections_) { + c.second->stop(); + } + connections_.clear(); + } +} + +bool local_uds_server_endpoint_impl::is_local() const { + return true; +} + +bool local_uds_server_endpoint_impl::send(const uint8_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "lse::send "; + for (uint32_t i = 0; i < _size; i++) + msg << std::setw(2) << std::setfill('0') << std::hex << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::lock_guard<std::mutex> its_lock(mutex_); + if (endpoint_impl::sending_blocked_) { + return false; + } + + client_t its_client; + std::memcpy(&its_client, &_data[protocol::COMMAND_HEADER_SIZE], sizeof(its_client)); + + connection::ptr its_connection; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + const auto its_iterator = connections_.find(its_client); + if (its_iterator == connections_.end()) { + return false; + } else { + its_connection = its_iterator->second; + } + } + + auto its_buffer = std::make_shared<message_buffer_t>(); + its_buffer->insert(its_buffer->end(), _data, _data + _size); + its_connection->send_queued(its_buffer); + + return true; +} + +bool local_uds_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_uds_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_uds_server_endpoint_impl::send_queued( + const target_data_iterator_type _it) { + + (void)_it; + + return false; +} + +void local_uds_server_endpoint_impl::receive() { + // intentionally left empty +} + +bool local_uds_server_endpoint_impl::get_default_target( + service_t, + local_uds_server_endpoint_impl::endpoint_type &) const { + + return false; +} + +bool local_uds_server_endpoint_impl::add_connection(const client_t &_client, + const std::shared_ptr<connection> &_connection) { + + bool ret = false; + std::lock_guard<std::mutex> its_lock(connections_mutex_); + auto find_connection = connections_.find(_client); + if (find_connection == connections_.end()) { + connections_[_client] = _connection; + ret = true; + } else { + VSOMEIP_WARNING << "Attempt to add already existing " + "connection to client " << std::hex << _client; + } + return ret; +} + +void local_uds_server_endpoint_impl::remove_connection( + const client_t &_client) { + + std::lock_guard<std::mutex> its_lock(connections_mutex_); + connections_.erase(_client); +} + +void local_uds_server_endpoint_impl::accept_cbk( + const connection::ptr& _connection, boost::system::error_code const &_error) { + if (_error != boost::asio::error::bad_descriptor + && _error != boost::asio::error::operation_aborted + && _error != boost::asio::error::no_descriptors) { + start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR << "local_usd_server_endpoint_impl::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms"; + auto its_timer = + std::make_shared<boost::asio::steady_timer>(io_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<local_uds_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error) { + if (!_error) { + its_ep->start(); + } + }); + } + + if (!_error) { +#ifndef __QNX__ + auto its_host = endpoint_host_.lock(); + client_t its_client = 0; + std::string its_client_host; + vsomeip_sec_client_t its_sec_client; + + its_sec_client.port = VSOMEIP_SEC_PORT_UNUSED; + its_sec_client.user = ANY_UID; + its_sec_client.group = ANY_GID; + + socket_type &its_socket = _connection->get_socket(); + if (auto creds = credentials::receive_credentials(its_socket.native_handle())) { + + its_client = std::get<0>(*creds); + its_client_host = std::get<3>(*creds); + + its_sec_client.user = std::get<1>(*creds); + its_sec_client.group = std::get<2>(*creds); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_host->get_client() + << " is rejecting new connection because client credentials couldn't be received!"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + + if (its_host && configuration_->is_security_enabled()) { + if (!configuration_->check_routing_credentials(its_client, &its_sec_client)) { + VSOMEIP_WARNING << "vSomeIP Security: Rejecting new connection with routing manager client ID 0x" + << std::hex << its_client + << " uid/gid= " << std::dec + << its_sec_client.user << "/" + << its_sec_client.group + << " because passed credentials do not match with routing manager credentials!"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + + if (is_routing_endpoint_) { + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later + _connection->set_bound_sec_client(its_sec_client); + _connection->set_bound_client_host(its_client_host); + } else { + { + std::lock_guard<std::mutex> its_connection_lock(connections_mutex_); + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later + const auto found_client = connections_.find(its_client); + if (found_client != connections_.end()) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << its_host->get_client() << " is rejecting new connection with client ID 0x" + << its_client << " uid/gid= " << std::dec + << its_sec_client.user << "/" + << its_sec_client.group + << " because of already existing connection using same client ID"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + } + + // Add to known clients (loads new config if needed) + std::shared_ptr<routing_host> its_routing_host = routing_host_.lock(); + its_routing_host->add_known_client(its_client, its_client_host); + + if (!configuration_->get_policy_manager()->check_credentials(its_client, &its_sec_client)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << its_host->get_client() << " received client credentials from client 0x" + << its_client << " which violates the security policy : uid/gid=" + << std::dec << its_sec_client.user << "/" + << its_sec_client.group; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> set later + _connection->set_bound_client(its_client); + _connection->set_bound_client_host(its_client_host); + add_connection(its_client, _connection); + } + } else { + configuration_->get_policy_manager()->store_client_to_sec_client_mapping(its_client, &its_sec_client); + configuration_->get_policy_manager()->store_sec_client_to_client_mapping(&its_sec_client, its_client); + + if (!is_routing_endpoint_) { + std::shared_ptr<routing_host> its_routing_host = routing_host_.lock(); + its_routing_host->add_known_client(its_client, its_client_host); + _connection->set_bound_client(its_client); + } + _connection->set_bound_client_host(its_client_host); + } +#endif + _connection->start(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// class local_service_impl::connection +/////////////////////////////////////////////////////////////////////////////// + +local_uds_server_endpoint_impl::connection::connection( + const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _initial_recv_buffer_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) + : socket_(_io), + server_(_server), + recv_buffer_size_initial_(_initial_recv_buffer_size + 8), + max_message_size_(_max_message_size), + recv_buffer_(recv_buffer_size_initial_, 0), + recv_buffer_size_(0), + missing_capacity_(0), + shrink_count_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold), + bound_client_(VSOMEIP_CLIENT_UNSET), + bound_client_host_(""), + assigned_client_(false), + is_stopped_(true) { + if (_server->is_routing_endpoint_ && + !_server->configuration_->is_security_enabled()) { + assigned_client_ = true; + } + + sec_client_.user = ANY_UID; + sec_client_.group = ANY_GID; +} + +local_uds_server_endpoint_impl::connection::ptr +local_uds_server_endpoint_impl::connection::create( + const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) { + const std::uint32_t its_initial_buffer_size + = static_cast<std::uint32_t>(protocol::COMMAND_HEADER_SIZE + + sizeof(instance_t) + sizeof(bool) + sizeof(bool)); + return ptr(new connection(_server, _max_message_size, its_initial_buffer_size, + _buffer_shrink_threshold, _io)); +} + +local_uds_server_endpoint_impl::socket_type & +local_uds_server_endpoint_impl::connection::get_socket() { + return socket_; +} + +std::unique_lock<std::mutex> +local_uds_server_endpoint_impl::connection::get_socket_lock() { + return std::unique_lock<std::mutex>(socket_mutex_); +} + +void local_uds_server_endpoint_impl::connection::start() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + const std::size_t its_capacity(recv_buffer_.capacity()); + if (recv_buffer_size_ > its_capacity) { + VSOMEIP_ERROR << __func__ << "Received buffer size is greater than the buffer capacity!" + << " recv_buffer_size_: " << recv_buffer_size_ + << " its_capacity: " << its_capacity; + return; + } + size_t left_buffer_size = its_capacity - recv_buffer_size_; + try { + if (missing_capacity_) { + if (missing_capacity_ > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!"; + return; + } + const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_); + if (its_capacity < its_required_capacity) { + // Make the resize to its_required_capacity + recv_buffer_.reserve(its_required_capacity); + recv_buffer_.resize(its_required_capacity, 0x0); + } + left_buffer_size = missing_capacity_; + missing_capacity_ = 0; + } else if (buffer_shrink_threshold_ + && shrink_count_ > buffer_shrink_threshold_ + && recv_buffer_size_ == 0) { + // In this case, make the resize to recv_buffer_size_initial_ + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + // And set buffer_size to recv_buffer_size_initial_, the same of our resize + left_buffer_size = recv_buffer_size_initial_; + shrink_count_ = 0; + } + } catch (const std::exception &e) { + handle_recv_buffer_exception(e); + // don't start receiving again + return; + } + + is_stopped_ = false; + auto its_storage = std::make_shared<local_endpoint_receive_op::storage>( + socket_, + std::bind( + &local_uds_server_endpoint_impl::connection::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4 + ), + &recv_buffer_[recv_buffer_size_], + left_buffer_size, + std::numeric_limits<std::uint32_t>::max(), + std::numeric_limits<std::uint32_t>::max(), + std::numeric_limits<std::size_t>::min() + ); + + socket_.async_wait(socket_type::wait_read, local_endpoint_receive_op::receive_cb(its_storage)); + } +} + +void local_uds_server_endpoint_impl::connection::stop() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + is_stopped_ = true; + if (socket_.is_open()) { + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } + boost::system::error_code its_error; + socket_.cancel(its_error); + } +} + +void local_uds_server_endpoint_impl::connection::send_queued( + const message_buffer_ptr_t& _buffer) { + + std::shared_ptr<local_uds_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "local_uds_server_endpoint_impl::connection::send_queued " + " couldn't lock server_"; + return; + } + + static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 }; + static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 }; + std::vector<boost::asio::const_buffer> bufs; + +#if 0 + std::stringstream msg; + msg << "lse::sq: "; + for (std::size_t i = 0; i < _buffer->size(); i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)(*_buffer)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + bufs.push_back(boost::asio::buffer(its_start_tag)); + bufs.push_back(boost::asio::buffer(*_buffer)); + bufs.push_back(boost::asio::buffer(its_end_tag)); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::asio::async_write( + socket_, + bufs, + std::bind( + &local_uds_server_endpoint_impl::connection::send_cbk, + shared_from_this(), + _buffer, + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +client_t local_uds_server_endpoint_impl::assign_client( + const byte_t *_data, uint32_t _size) { + + std::vector<byte_t> its_data(_data, _data + _size); + + protocol::assign_client_command its_command; + protocol::error_e its_error; + + its_command.deserialize(its_data, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ + << ": assign client command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return VSOMEIP_CLIENT_UNSET; + } + + return utility::request_client_id(configuration_, + its_command.get_name(), its_command.get_client()); +} + +void local_uds_server_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, + method_t _method, std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + (void)_service; + (void)_method; + (void)_debouncing; + (void)_maximum_retention; + VSOMEIP_ERROR << "local_uds_server_endpoint_impl::get_configured_times_from_endpoint."; +} + +void local_uds_server_endpoint_impl::connection::send_cbk(const message_buffer_ptr_t _buffer, + boost::system::error_code const &_error, std::size_t _bytes) { + (void)_buffer; + (void)_bytes; + if (_error) + VSOMEIP_WARNING << "sei::send_cbk received error: " << _error.message(); +} + +void local_uds_server_endpoint_impl::connection::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes, + std::uint32_t const &_uid, std::uint32_t const &_gid) +{ + std::shared_ptr<local_uds_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "local_uds_server_endpoint_impl::connection::receive_cbk " + " couldn't lock server_"; + return; + } + std::shared_ptr<routing_host> its_host = its_server->routing_host_.lock(); + if (!its_host) + return; + + std::shared_ptr<vsomeip_v3::configuration> its_config = its_server->configuration_; + if (_error == boost::asio::error::operation_aborted) { + if (its_server->is_routing_endpoint_ && + bound_client_ != VSOMEIP_CLIENT_UNSET && its_config) { + utility::release_client_id(its_config->get_network(), + bound_client_); + set_bound_client(VSOMEIP_CLIENT_UNSET); + } + + // connection was stopped + return; + } + + bool is_error(false); + std::size_t its_start = 0; + std::size_t its_end = 0; + std::size_t its_iteration_gap = 0; + std::uint32_t its_command_size = 0; + + if (!_error && 0 < _bytes) { +#if 0 + std::stringstream msg; + msg << "lse::c<" << this << ">rcb: "; + for (std::size_t i = 0; i < _bytes + recv_buffer_size_; i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int) (recv_buffer_[i]) << " "; + VSOMEIP_INFO << msg.str(); +#endif + + if (recv_buffer_size_ + _bytes < recv_buffer_size_) { + VSOMEIP_ERROR << "receive buffer overflow in local server endpoint ~> abort!"; + return; + } + recv_buffer_size_ += _bytes; + + bool message_is_empty(false); + bool found_message(false); + + do { + found_message = false; + message_is_empty = false; + + its_start = 0 + its_iteration_gap; + if (its_start + 3 < its_start) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + while (its_start + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_start] != 0x67 || + recv_buffer_[its_start+1] != 0x37 || + recv_buffer_[its_start+2] != 0x6d || + recv_buffer_[its_start+3] != 0x07)) { + its_start++; + } + + if (its_start + 3 == recv_buffer_size_ + its_iteration_gap) { + message_is_empty = true; + } else { + its_start += 4; + } + + if (!message_is_empty) { + if (its_start + protocol::COMMAND_POSITION_SIZE + 3 < recv_buffer_size_ + its_iteration_gap) { + its_command_size = bithelper::read_uint32_le(&recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE]); + its_end = its_start + protocol::COMMAND_POSITION_SIZE + 3 + its_command_size; + } else { + its_end = its_start; + } + if (its_command_size && max_message_size_ != MESSAGE_SIZE_UNLIMITED + && its_command_size > max_message_size_) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Received a local message which exceeds " + << "maximum message size (" << std::dec << its_command_size + << ") aborting! local: " << get_path_local() << " remote: " + << get_path_remote(); + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + return; + } + if (its_end + 3 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + while (its_end + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_end] != 0x07 || + recv_buffer_[its_end+1] != 0x6d || + recv_buffer_[its_end+2] != 0x37 || + recv_buffer_[its_end+3] != 0x67)) { + its_end ++; + } + if (its_end + 4 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + // check if we received a full message + if (recv_buffer_size_ + its_iteration_gap < its_end + 4 + || recv_buffer_[its_end] != 0x07 + || recv_buffer_[its_end+1] != 0x6d + || recv_buffer_[its_end+2] != 0x37 + || recv_buffer_[its_end+3] != 0x67) { + // command (1 Byte) + version (2 Byte) + client id (2 Byte) + // + command size (4 Byte) + data itself + stop tag (4 byte) + // = 13 Bytes not covered in command size. + // If need to change the recv_buffer_, change the value of missing_capacity_ + // in this if/else, otherwise it is 0 + if (its_start - its_iteration_gap + its_command_size + + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE > recv_buffer_size_) { + missing_capacity_ = + std::uint32_t(its_start) - std::uint32_t(its_iteration_gap) + + its_command_size + std::uint32_t(protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) + - std::uint32_t(recv_buffer_size_); + } else if (recv_buffer_size_ < protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) { + // to little data to read out the command size + // minimal amount of data needed to read out command size = header + tag size + missing_capacity_ = static_cast<std::uint32_t>( + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE - recv_buffer_size_); + } else { + std::stringstream local_msg; + local_msg << std::setfill('0') << std::hex; + for (std::size_t i = its_iteration_gap; + i < recv_buffer_size_ + its_iteration_gap && + i - its_iteration_gap < 32; i++) { + local_msg << std::setw(2) << (int) recv_buffer_[i] << " "; + } + VSOMEIP_ERROR << "lse::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << recv_buffer_size_ << " but couldn't read " + "out command size. recv_buffer_capacity: " + << std::dec << recv_buffer_.capacity() + << " its_iteration_gap: " << std::dec + << its_iteration_gap << " bound client: 0x" + << std::hex << bound_client_ << " buffer: " + << local_msg.str(); + recv_buffer_size_ = 0; + missing_capacity_ = 0; + its_iteration_gap = 0; + message_is_empty = true; + } + } + } + + if (!message_is_empty && + its_end + 3 < recv_buffer_size_ + its_iteration_gap) { + + if (its_server->is_routing_endpoint_ + && recv_buffer_[its_start] == byte_t(protocol::id_e::ASSIGN_CLIENT_ID)) { + client_t its_client = its_server->assign_client( + &recv_buffer_[its_start], uint32_t(its_end - its_start)); + + if (its_config && its_config->is_security_enabled()) { + // Add to known clients (loads new config if needed) + its_host->add_known_client(its_client, get_bound_client_host()); + + if (!its_server->add_connection(its_client, shared_from_this())) { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " is rejecting new connection with client ID 0x" << its_client + << " uid/gid= " << std::dec + << sec_client_.user << "/" + << sec_client_.group + << " because of already existing connection using same client ID"; + stop(); + return; + } else if (!its_server->configuration_->get_policy_manager()->check_credentials( + its_client, &sec_client_)) { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " received client credentials from client 0x" << its_client + << " which violates the security policy : uid/gid=" + << std::dec << sec_client_.user << "/" + << sec_client_.group; + its_server->remove_connection(its_client); + utility::release_client_id(its_config->get_network(), + its_client); + stop(); + return; + } + else { + set_bound_client(its_client); + } + } else { + set_bound_client(its_client); + its_host->add_known_client(its_client, get_bound_client_host()); + its_server->add_connection(its_client, shared_from_this()); + } + its_server->send_client_identifier(its_client); + assigned_client_ = true; + } else if (!its_server->is_routing_endpoint_ || assigned_client_) { + + vsomeip_sec_client_t its_sec_client{}; + + its_sec_client.port = VSOMEIP_SEC_PORT_UNUSED; + its_sec_client.user = _uid; + its_sec_client.group = _gid; + + its_host->on_message(&recv_buffer_[its_start], + uint32_t(its_end - its_start), its_server.get(), + false, bound_client_, &its_sec_client); + } else { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " didn't receive VSOMEIP_ASSIGN_CLIENT as first message"; + } + #if 0 + std::stringstream local_msg; + local_msg << "lse::c<" << this << ">rcb::thunk: "; + for (std::size_t i = its_start; i < its_end; i++) + local_msg << std::setw(2) << std::setfill('0') << std::hex + << (int) recv_buffer_[i] << " "; + VSOMEIP_INFO << local_msg.str(); + #endif + calculate_shrink_count(); + recv_buffer_size_ -= (its_end + 4 - its_iteration_gap); + missing_capacity_ = 0; + its_command_size = 0; + found_message = true; + its_iteration_gap = its_end + 4; + } else { + if (its_iteration_gap) { + // Message not complete and not in front of the buffer! + // Copy last part to front for consume in future receive_cbk call! + for (size_t i = 0; i < recv_buffer_size_; ++i) { + recv_buffer_[i] = recv_buffer_[i + its_iteration_gap]; + } + // Still more capacity needed after shifting everything to front? + if (missing_capacity_ && + missing_capacity_ <= recv_buffer_.capacity() - recv_buffer_size_) { + missing_capacity_ = 0; + } + } else if (message_is_empty) { + VSOMEIP_ERROR << "Received garbage data."; + is_error = true; + } + } + } while (recv_buffer_size_ > 0 && found_message); + } + + if (is_stopped_ + || _error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset + || is_error) { + shutdown_and_close(); + its_server->remove_connection(bound_client_); + its_server->configuration_->get_policy_manager()->remove_client_to_sec_client_mapping(bound_client_); + } else if (_error != boost::asio::error::bad_descriptor) { + start(); + } +} + +void local_uds_server_endpoint_impl::connection::set_bound_client(client_t _client) { + bound_client_ = _client; +} + +client_t local_uds_server_endpoint_impl::connection::get_bound_client() const { + return bound_client_; +} + +void local_uds_server_endpoint_impl::connection::set_bound_client_host( + const std::string &_bound_client_host) { + + bound_client_host_ = _bound_client_host; +} + +std::string local_uds_server_endpoint_impl::connection::get_bound_client_host() const { + return bound_client_host_; +} + + +void local_uds_server_endpoint_impl::connection::set_bound_sec_client( + const vsomeip_sec_client_t &_sec_client) { + + sec_client_ = _sec_client; +} + +void local_uds_server_endpoint_impl::connection::calculate_shrink_count() { + if (buffer_shrink_threshold_) { + if (recv_buffer_.capacity() != recv_buffer_size_initial_) { + if (recv_buffer_size_ < (recv_buffer_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + } +} + +std::string local_uds_server_endpoint_impl::connection::get_path_local() const { + boost::system::error_code ec; + std::string its_local_path; + if (socket_.is_open()) { + endpoint_type its_local_endpoint = socket_.local_endpoint(ec); + if (!ec) { + its_local_path += its_local_endpoint.path(); + } + } + return its_local_path; +} + +std::string local_uds_server_endpoint_impl::connection::get_path_remote() const { + boost::system::error_code ec; + std::string its_remote_path; + if (socket_.is_open()) { + endpoint_type its_remote_endpoint = socket_.remote_endpoint(ec); + if (!ec) { + its_remote_path += its_remote_endpoint.path(); + } + } + return its_remote_path; +} + +void local_uds_server_endpoint_impl::connection::handle_recv_buffer_exception( + const std::exception &_e) { + std::stringstream its_message; + its_message << "local_uds_server_endpoint_impl::connection catched exception" + << _e.what() << " local: " << get_path_local() << " remote: " + << get_path_remote() << " shutting down connection. Start of buffer: " + << std::setfill('0') << std::hex; + + for (std::size_t i = 0; i < recv_buffer_size_ && i < 16; i++) { + its_message << std::setw(2) << (int) (recv_buffer_[i]) << " "; + } + + its_message << " Last 16 Bytes captured: "; + for (int i = 15; recv_buffer_size_ > 15u && i >= 0; i--) { + its_message << std::setw(2) << (int) (recv_buffer_[static_cast<size_t>(i)]) << " "; + } + VSOMEIP_ERROR << its_message.str(); + recv_buffer_.clear(); + if (socket_.is_open()) { + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } + + } + std::shared_ptr<local_uds_server_endpoint_impl> its_server = server_.lock(); + if (its_server) { + its_server->remove_connection(bound_client_); + } +} + +std::size_t +local_uds_server_endpoint_impl::connection::get_recv_buffer_capacity() const { + return recv_buffer_.capacity(); +} + +void +local_uds_server_endpoint_impl::connection::shutdown_and_close() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + shutdown_and_close_unlocked(); +} + +void +local_uds_server_endpoint_impl::connection::shutdown_and_close_unlocked() { + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); +} + +void local_uds_server_endpoint_impl::print_status() { + std::lock_guard<std::mutex> its_lock(mutex_); + connections_t its_connections; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + its_connections = connections_; + } + + std::string its_local_path(local_.path()); + + VSOMEIP_INFO << "status lse: " << its_local_path << " connections: " + << std::dec << its_connections.size() << " targets: " + << std::dec << targets_.size(); + for (const auto &c : its_connections) { + std::string its_remote_path; // TODO: construct the path + + std::size_t its_recv_size(0); + { + std::unique_lock<std::mutex> c_s_lock(c.second->get_socket_lock()); + its_recv_size = c.second->get_recv_buffer_capacity(); + } + + VSOMEIP_INFO << "status lse: client: " << its_remote_path + << " recv_buffer: " << std::dec << its_recv_size; + } +} + +std::string local_uds_server_endpoint_impl::get_remote_information( + const target_data_iterator_type _it) const { + + (void)_it; + return "local"; +} + +std::string local_uds_server_endpoint_impl::get_remote_information( + const endpoint_type& _remote) const { + + (void)_remote; + return "local"; +} + +bool local_uds_server_endpoint_impl::is_reliable() const { + return false; +} + +std::uint16_t local_uds_server_endpoint_impl::get_local_port() const { + + return 0; +} + +void local_uds_server_endpoint_impl::set_local_port(std::uint16_t _port) { + + (void)_port; + // Intentionally left empty +} + +bool local_uds_server_endpoint_impl::check_packetizer_space( + target_data_iterator_type _it, message_buffer_ptr_t* _packetizer, + std::uint32_t _size) { + + if ((*_packetizer)->size() + _size < (*_packetizer)->size()) { + VSOMEIP_ERROR << "Overflow in packetizer addition ~> abort sending!"; + return false; + } + if ((*_packetizer)->size() + _size > max_message_size_ + && !(*_packetizer)->empty()) { + _it->second.queue_.push_back(std::make_pair(*_packetizer, 0)); + _it->second.queue_size_ += (*_packetizer)->size(); + *_packetizer = std::make_shared<message_buffer_t>(); + } + return true; +} + +void +local_uds_server_endpoint_impl::send_client_identifier( + const client_t &_client) { + + protocol::assign_client_ack_command its_command; + its_command.set_client(VSOMEIP_ROUTING_CLIENT); + its_command.set_assigned(_client); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << __func__ + << ": assign client ack command serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return; + } + + send(&its_buffer[0], static_cast<uint32_t>(its_buffer.size())); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/netlink_connector.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/netlink_connector.cpp new file mode 100644 index 00000000000..f81e0abaf48 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/netlink_connector.cpp @@ -0,0 +1,484 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(__linux__) || defined(ANDROID) + +#include <thread> + +#include <boost/asio/write.hpp> +#include <boost/asio/read.hpp> +#include<sstream> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/netlink_connector.hpp" + +namespace vsomeip_v3 { + +void netlink_connector::register_net_if_changes_handler(const net_if_changed_handler_t& _handler) { + handler_ = _handler; +} + +void netlink_connector::unregister_net_if_changes_handler() { + handler_ = nullptr; +} + +void netlink_connector::stop() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + if (its_error) { + VSOMEIP_WARNING << "Error closing NETLINK socket!"; + } +} + +void netlink_connector::start() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::system::error_code ec; + if (socket_.is_open()) { + socket_.close(ec); + if (ec) { + VSOMEIP_WARNING << "Error closing NETLINK socket: " << ec.message(); + } + } + socket_.open(nl_protocol(NETLINK_ROUTE), ec); + if (ec) { + VSOMEIP_WARNING << "Error opening NETLINK socket: " << ec.message(); + if (handler_) { + handler_(true, "n/a", true); + handler_(false, "n/a", true); + } + return; + } + if (socket_.is_open()) { + socket_.bind(nl_endpoint<nl_protocol>( + RTMGRP_LINK | + RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | + RTMGRP_IPV4_MROUTE | RTMGRP_IPV6_MROUTE), ec); + + if (ec && ec != boost::asio::error::address_in_use) { + VSOMEIP_WARNING << "Error binding NETLINK socket: " << ec.message(); + if (handler_) { + handler_(true, "n/a", true); + handler_(false, "n/a", true); + } + + return; + } + + send_ifa_request(); + + socket_.async_receive( + boost::asio::buffer(&recv_buffer_[0], recv_buffer_size), + std::bind( + &netlink_connector::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } else { + VSOMEIP_WARNING << "Error opening NETLINK socket!"; + if (handler_) { + handler_(true, "n/a", true); + handler_(false, "n/a", true); + } + } +} + +void netlink_connector::receive_cbk(boost::system::error_code const &_error, + std::size_t _bytes) { + if (!_error) { + size_t len = _bytes; + + unsigned int address(0); + if (address_.is_v4()) { + inet_pton(AF_INET, address_.to_string().c_str(), &address); + } else { + inet_pton(AF_INET6, address_.to_string().c_str(), &address); + } + + struct nlmsghdr *nlh = (struct nlmsghdr *)&recv_buffer_[0]; + + while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) { + char ifname[IF_NAMESIZE]; + switch (nlh->nlmsg_type) { + case RTM_NEWADDR: { + // New Address information + struct ifaddrmsg *ifa = (ifaddrmsg *)NLMSG_DATA(nlh); + if (has_address(ifa, IFA_PAYLOAD(nlh), address)) { + net_if_index_for_address_ = static_cast<int>(ifa->ifa_index); + auto its_if = net_if_flags_.find(static_cast<int>(ifa->ifa_index)); + if (its_if != net_if_flags_.end()) { + if ((its_if->second & IFF_UP) && + (is_requiring_link_ ? (its_if->second & IFF_RUNNING) : true)) { + if (handler_) { + if_indextoname(ifa->ifa_index,ifname); + handler_(true, ifname, true); + send_rt_request(); + } + } else { + if (handler_) { + if_indextoname(ifa->ifa_index,ifname); + handler_(true, ifname, false); + } + } + } else { + // Request interface information + // as we don't know about up/running state! + send_ifi_request(); + } + } + break; + } + case RTM_NEWLINK: { + // New Interface information + struct ifinfomsg *ifi = (ifinfomsg *)NLMSG_DATA(nlh); + net_if_flags_[ifi->ifi_index] = ifi->ifi_flags; + if (net_if_index_for_address_ == ifi->ifi_index) { + if ((ifi->ifi_flags & IFF_UP) && + (is_requiring_link_ ? (ifi->ifi_flags & IFF_RUNNING) : true)) { + if (handler_) { + if_indextoname(static_cast<unsigned int>(ifi->ifi_index),ifname); + handler_(true, ifname, true); + send_rt_request(); + } + } else { + if (handler_) { + if_indextoname(static_cast<unsigned int>(ifi->ifi_index),ifname); + handler_(true, ifname, false); + } + } + } + break; + } + case RTM_NEWROUTE: { + struct rtmsg *routemsg = (rtmsg *)NLMSG_DATA(nlh); + std::string its_route_name; + if (check_sd_multicast_route_match(routemsg, RTM_PAYLOAD(nlh), + &its_route_name)) { + if (handler_) { + handler_(false, its_route_name, true); + } + } + break; + } + case RTM_DELROUTE: { + struct rtmsg *routemsg = (rtmsg *)NLMSG_DATA(nlh); + std::string its_route_name; + if (check_sd_multicast_route_match(routemsg, RTM_PAYLOAD(nlh), + &its_route_name)) { + if (handler_) { + handler_(false, its_route_name, false); + } + } + break; + } + case NLMSG_ERROR: { + struct nlmsgerr *errmsg = (nlmsgerr *)NLMSG_DATA(nlh); + if (errmsg->error != 0) { + handle_netlink_error(errmsg); + } + break; + } + case NLMSG_DONE: + case NLMSG_NOOP: + default: + break; + } + nlh = NLMSG_NEXT(nlh, len); + } + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + socket_.async_receive( + boost::asio::buffer(&recv_buffer_[0], recv_buffer_size), + std::bind( + &netlink_connector::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } + } + } else { + if (_error != boost::asio::error::operation_aborted) { + VSOMEIP_WARNING << "Error receive_cbk NETLINK socket!" << _error.message(); + boost::system::error_code its_error; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + if (its_error) { + VSOMEIP_WARNING << "Error closing NETLINK socket!" + << its_error.message(); + } + } + } + if (handler_) { + handler_(true, "n/a", true); + handler_(false, "n/a", true); + } + } + } +} + +void netlink_connector::send_cbk(boost::system::error_code const &_error, std::size_t _bytes) { + (void)_bytes; + if (_error) { + VSOMEIP_WARNING << "Netlink send error : " << _error.message(); + if (handler_) { + handler_(true, "n/a", true); + handler_(false, "n/a", true); + } + } +} + +void netlink_connector::send_ifa_request(std::uint32_t _retry) { + typedef struct { + struct nlmsghdr nlhdr; + struct ifaddrmsg addrmsg; + } netlink_address_msg; + netlink_address_msg get_address_msg; + memset(&get_address_msg, 0, sizeof(get_address_msg)); + get_address_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + get_address_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + get_address_msg.nlhdr.nlmsg_type = RTM_GETADDR; + // the sequence number has stored the request sequence and the retry count. + // request sequece is stored in the LSB (least significant byte) and + // retry is stored in the 2nd LSB. + get_address_msg.nlhdr.nlmsg_seq = ifa_request_sequence_ | (_retry << retry_bit_shift_); + if (address_.is_v4()) { + get_address_msg.addrmsg.ifa_family = AF_INET; + } else { + get_address_msg.addrmsg.ifa_family = AF_INET6; + } + + socket_.async_send( + boost::asio::buffer(&get_address_msg, get_address_msg.nlhdr.nlmsg_len), + std::bind( + &netlink_connector::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); +} + +void netlink_connector::send_ifi_request(std::uint32_t _retry) { + typedef struct { + struct nlmsghdr nlhdr; + struct ifinfomsg infomsg; + } netlink_link_msg; + netlink_link_msg get_link_msg; + memset(&get_link_msg, 0, sizeof(get_link_msg)); + get_link_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + get_link_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + get_link_msg.nlhdr.nlmsg_type = RTM_GETLINK; + get_link_msg.infomsg.ifi_family = AF_UNSPEC; + // the sequence number has stored the request sequence and the retry count. + // request sequece is stored in the LSB (least significant byte) and + // retry is stored in the 2nd LSB. + get_link_msg.nlhdr.nlmsg_seq = ifi_request_sequence_ | (_retry << retry_bit_shift_); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + socket_.async_send( + boost::asio::buffer(&get_link_msg, get_link_msg.nlhdr.nlmsg_len), + std::bind( + &netlink_connector::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +void netlink_connector::send_rt_request(std::uint32_t _retry) { + typedef struct { + struct nlmsghdr nlhdr; + struct rtgenmsg routemsg; + } netlink_route_msg; + + netlink_route_msg get_route_msg; + memset(&get_route_msg, 0, sizeof(get_route_msg)); + get_route_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + get_route_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + get_route_msg.nlhdr.nlmsg_type = RTM_GETROUTE; + // the sequence number has stored the request sequence and the retry count. + // request sequece is stored in the LSB (least significant byte) and + // retry is stored in the 2nd LSB. + get_route_msg.nlhdr.nlmsg_seq = rt_request_sequence_ | (_retry << retry_bit_shift_); + if (multicast_address_.is_v6()) { + get_route_msg.routemsg.rtgen_family = AF_INET6; + } else { + get_route_msg.routemsg.rtgen_family = AF_INET; + } + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + socket_.async_send( + boost::asio::buffer(&get_route_msg, get_route_msg.nlhdr.nlmsg_len), + std::bind( + &netlink_connector::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +void netlink_connector::handle_netlink_error(struct nlmsgerr *_error_msg) { + // the sequence number has stored the request sequence and the retry count. + // retry is stored in the 2nd LSB. + std::uint32_t retry = _error_msg->msg.nlmsg_seq >> retry_bit_shift_; + if (retry >= max_retries_) { + VSOMEIP_ERROR << "netlink_connector::receive_cbk received " + "error message: " << strerror(-_error_msg->error) + << " type " << std::dec << _error_msg->msg.nlmsg_type + << " seq " << _error_msg->msg.nlmsg_seq; + return; + } + + // the sequence number has stored the request sequence and the retry count. + // request sequece is stored in the LSB. + std::uint32_t request_sequence = _error_msg->msg.nlmsg_seq & request_sequence_bitmask_; + std::string request_type{}; + if (_error_msg->msg.nlmsg_type == RTM_GETADDR && request_sequence == ifa_request_sequence_) { + request_type = "address request"; + send_ifa_request(retry + 1); + } else if (_error_msg->msg.nlmsg_type == RTM_GETLINK && request_sequence == ifi_request_sequence_) { + request_type = "link request"; + send_ifi_request(retry + 1); + } else if (_error_msg->msg.nlmsg_type == RTM_GETROUTE && request_sequence == rt_request_sequence_) { + request_type = "route request"; + send_rt_request(retry + 1); + } + + if (!request_type.empty()) { + VSOMEIP_INFO << "Retrying netlink " << request_type; + } +} + +bool netlink_connector::has_address(struct ifaddrmsg * ifa_struct, + size_t length, + const unsigned int address) { + + struct rtattr *retrta; + retrta = static_cast<struct rtattr *>(IFA_RTA(ifa_struct)); + while RTA_OK(retrta, length) { + if (retrta->rta_type == IFA_ADDRESS) { + char pradd[128]; + unsigned int * tmp_address = (unsigned int *)RTA_DATA(retrta); + if (address_.is_v4()) { + inet_ntop(AF_INET, tmp_address, pradd, sizeof(pradd)); + } else { + inet_ntop(AF_INET6, tmp_address, pradd, sizeof(pradd)); + } + if (address == *tmp_address) { + return true; + } + } + retrta = RTA_NEXT(retrta, length); + } + + return false; +} + +bool netlink_connector::check_sd_multicast_route_match(struct rtmsg* _routemsg, + size_t _length, + std::string* _routename) const { + struct rtattr *retrta; + retrta = static_cast<struct rtattr *>(RTM_RTA(_routemsg)); + int if_index(0); + char if_name[IF_NAMESIZE] = "n/a"; + char address[INET6_ADDRSTRLEN] = "n/a"; + char gateway[INET6_ADDRSTRLEN] = "n/a"; + bool matches_sd_multicast(false); + while (RTA_OK(retrta, _length)) { + if (retrta->rta_type == RTA_DST) { + // check if added/removed route matches on configured SD multicast address + size_t rtattr_length = RTA_PAYLOAD(retrta); + if (rtattr_length == 4 && multicast_address_.is_v4()) { // IPv4 route + inet_ntop(AF_INET, RTA_DATA(retrta), address, sizeof(address)); + std::uint32_t netmask(0); + for (int i = 31; i > 31 - _routemsg->rtm_dst_len; i--) { + netmask |= static_cast<std::uint32_t>(1 << i); + } + const std::uint32_t dst_addr = ntohl(*((std::uint32_t *)RTA_DATA(retrta))); + const std::uint32_t dst_net = (dst_addr & netmask); + const std::uint32_t sd_addr = static_cast<std::uint32_t>(multicast_address_.to_v4().to_ulong()); + const std::uint32_t sd_net = (sd_addr & netmask); + matches_sd_multicast = !(dst_net ^ sd_net); + } else if (rtattr_length == 16 && multicast_address_.is_v6()) { // IPv6 route + inet_ntop(AF_INET6, RTA_DATA(retrta), address, sizeof(address)); + std::uint32_t netmask2[4] = {0,0,0,0}; + for (int i = 127; i > 127 - _routemsg->rtm_dst_len; i--) { + if (i > 95) { + netmask2[0] |= static_cast<std::uint32_t>(1 << (i-96)); + } else if (i > 63) { + netmask2[1] |= static_cast<std::uint32_t>(1 << (i-64)); + } else if (i > 31) { + netmask2[2] |= static_cast<std::uint32_t>(1 << (i-32)); + } else { + netmask2[3] |= static_cast<std::uint32_t>(1 << i); + } + } + + for (int i = 0; i < 4; i++) { +#ifndef ANDROID + const std::uint32_t dst = ntohl((*(struct in6_addr*)RTA_DATA(retrta)).__in6_u.__u6_addr32[i]); +#else + const std::uint32_t dst = ntohl((*(struct in6_addr*)RTA_DATA(retrta)).in6_u.u6_addr32[i]); +#endif + const std::uint32_t sd = ntohl(reinterpret_cast<std::uint32_t*>(multicast_address_.to_v6().to_bytes().data())[i]); + const std::uint32_t dst_net = dst & netmask2[i]; + const std::uint32_t sd_net = sd & netmask2[i]; + matches_sd_multicast = !(dst_net ^ sd_net); + if (!matches_sd_multicast) { + break; + } + } + } + } else if (retrta->rta_type == RTA_OIF) { + if_index = *(int *)(RTA_DATA(retrta)); + if_indextoname(static_cast<unsigned int>(if_index),if_name); + } else if (retrta->rta_type == RTA_GATEWAY) { + size_t rtattr_length = RTA_PAYLOAD(retrta); + if (rtattr_length == 4) { + inet_ntop(AF_INET, RTA_DATA(retrta), gateway, sizeof(gateway)); + } else if (rtattr_length == 16) { + inet_ntop(AF_INET6, RTA_DATA(retrta), gateway, sizeof(gateway)); + } + } + retrta = RTA_NEXT(retrta, _length); + } + if (matches_sd_multicast && net_if_index_for_address_ == if_index) { + std::stringstream stream; + stream << address << "/" << (static_cast<uint32_t>(_routemsg->rtm_dst_len)) + << " if: " << if_name << " gw: " << gateway; + *_routename = stream.str(); + return true; + } else if (if_index > 0 && net_if_index_for_address_ == if_index && + _routemsg->rtm_dst_len == 0) { + // the default route is set to the interface on which the SD will listen + // therefore no explicit multicast route is required. + std::stringstream stream; + stream << "default route (0.0.0.0/0) if: " << if_name << " gw: " << gateway; + *_routename = stream.str(); + return true; + } + return false; +} + +} // namespace vsomeip_v3 + +#endif // __linux__ or ANDROID diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/server_endpoint_impl.cpp new file mode 100644 index 00000000000..97f43d49bfa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/server_endpoint_impl.cpp @@ -0,0 +1,872 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <memory> +#include <sstream> +#include <limits> +#include <thread> +#include <algorithm> + +#include <boost/asio/buffer.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/local/stream_protocol.hpp> +#include <boost/asio/ip/udp.hpp> + +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/server_endpoint_impl.hpp" +#include "../include/endpoint_definition.hpp" + +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" +#include "../../service_discovery/include/defines.hpp" + +namespace vsomeip_v3 { + +template<typename Protocol> +server_endpoint_impl<Protocol>::server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) + : endpoint_impl<Protocol>(_endpoint_host, _routing_host, _io, _configuration) { +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::prepare_stop( + const endpoint::prepare_stop_handler_t &_handler, service_t _service) { + + std::lock_guard<std::mutex> its_lock(mutex_); + std::vector<target_data_iterator_type> its_erased; + boost::system::error_code ec; + + if (_service == ANY_SERVICE) { + endpoint_impl<Protocol>::sending_blocked_ = true; + if (std::all_of(targets_.begin(), targets_.end(), + [&](const typename target_data_type::value_type &_t) + { return _t.second.queue_.empty(); })) { + // nothing was queued and all queues are empty -> ensure cbk is called + auto ptr = this->shared_from_this(); + endpoint_impl<Protocol>::io_.post( + [ptr, _handler]() { _handler(ptr); }); + } else { + prepare_stop_handlers_[_service] = _handler; + } + + for (auto t = targets_.begin(); t != targets_.end(); t++) { + auto its_train (t->second.train_); + // cancel dispatch timer + t->second.dispatch_timer_->cancel(ec); + if (its_train->buffer_->size() > 0) { + if (queue_train(t, its_train)) + its_erased.push_back(t); + } + } + } else { + // check if any of the queues contains a message of to be stopped service + bool found_service_msg(false); + for (const auto &t : targets_) { + for (const auto &q : t.second.queue_) { + const service_t its_service = bithelper::read_uint16_be(&(*q.first)[VSOMEIP_SERVICE_POS_MIN]); + if (its_service == _service) { + found_service_msg = true; + break; + } + } + if (found_service_msg) { + break; + } + } + if (found_service_msg) { + prepare_stop_handlers_[_service] = _handler; + } else { // no messages of the to be stopped service are or have been queued + auto ptr = this->shared_from_this(); + endpoint_impl<Protocol>::io_.post( + [ptr, _handler]() { _handler(ptr); }); + } + + for (auto t = targets_.begin(); t != targets_.end(); t++) { + auto its_train(t->second.train_); + for (auto const& passenger_iter : its_train->passengers_) { + if (passenger_iter.first == _service) { + // cancel dispatch timer + t->second.dispatch_timer_->cancel(ec); + // TODO: Queue all(!) trains here... + if (queue_train(t, its_train)) + its_erased.push_back(t); + break; + } + } + } + } + + for (const auto t : its_erased) + targets_.erase(t); +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::stop() { +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::is_client() const { + return false; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::restart(bool _force) { + (void)_force; + + boost::system::error_code its_error; + this->init(server_endpoint_impl<Protocol>::local_, its_error); + this->start(); +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::is_established() const { + return true; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::is_established_or_connected() const { + return true; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::set_established(bool _established) { + (void) _established; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::set_connected(bool _connected) { + (void) _connected; +} + +template<typename Protocol>bool server_endpoint_impl<Protocol>::send(const uint8_t *_data, + uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "sei::send "; + for (uint32_t i = 0; i < _size; i++) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + endpoint_type its_target; + bool is_valid_target(false); + + if (VSOMEIP_SESSION_POS_MAX < _size) { + std::lock_guard<std::mutex> its_lock(mutex_); + + if(endpoint_impl<Protocol>::sending_blocked_) { + return false; + } + + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + + clients_mutex_.lock(); + auto found_client = clients_.find(its_client); + if (found_client != clients_.end()) { + auto found_session = found_client->second.find(its_session); + if (found_session != found_client->second.end()) { + its_target = found_session->second; + is_valid_target = true; + found_client->second.erase(its_session); + } else { + VSOMEIP_WARNING << "server_endpoint::send: session_id 0x" + << std::hex << its_session + << " not found for client 0x" << its_client; + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == VSOMEIP_SD_SERVICE + && its_method == VSOMEIP_SD_METHOD) { + VSOMEIP_ERROR << "Clearing clients map as a request was " + "received on SD port"; + clients_.clear(); + is_valid_target = get_default_target(its_service, its_target); + } + } + } else { + is_valid_target = get_default_target(its_service, its_target); + } + clients_mutex_.unlock(); + + if (is_valid_target) { + is_valid_target = send_intern(its_target, _data, _size); + } + } + return is_valid_target; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::send( + const std::vector<byte_t>& _cmd_header, const byte_t *_data, + uint32_t _size) { + (void) _cmd_header; + (void) _data; + (void) _size; + return false; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::send_intern( + endpoint_type _target, const byte_t *_data, uint32_t _size) { + + switch (check_message_size(_data, _size, _target)) { + case endpoint_impl<Protocol>::cms_ret_e::MSG_WAS_SPLIT: + return true; + break; + case endpoint_impl<Protocol>::cms_ret_e::MSG_TOO_BIG: + return false; + break; + case endpoint_impl<Protocol>::cms_ret_e::MSG_OK: + default: + break; + } + if (!prepare_stop_handlers_.empty()) { + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + if (prepare_stop_handlers_.find(its_service) != prepare_stop_handlers_.end()) { + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_WARNING << "server_endpoint::send: Service is stopping, ignoring message: [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_client << "." + << std::setw(4) << its_session << "]"; + return false; + } + } + + const auto its_target_iterator = find_or_create_target_unlocked(_target); + auto &its_data(its_target_iterator->second); + + bool must_depart(false); + auto its_now(std::chrono::steady_clock::now()); + +#if 0 + std::stringstream msg; + msg << "sei::send_intern: "; + for (uint32_t i = 0; i < _size; i++) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_DEBUG << msg.str(); +#endif + // STEP 1: Check queue limit + if (!check_queue_limit(_data, _size, its_data)) { + return false; + } + + // STEP 2: Cancel the dispatch timer + cancel_dispatch_timer(its_target_iterator); + + // STEP 3: Get configured timings + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + + std::chrono::nanoseconds its_debouncing(0), its_retention(0); + if (its_service != VSOMEIP_SD_SERVICE && its_method != VSOMEIP_SD_METHOD) { + get_configured_times_from_endpoint(its_service, its_method, + &its_debouncing, &its_retention); + } + + // STEP 4: Check if the passenger enters an empty train + const std::pair<service_t, method_t> its_identifier + = std::make_pair(its_service, its_method); + if (its_data.train_->passengers_.empty()) { + its_data.train_->departure_ = its_now + its_retention; + } else { + if (its_data.train_->passengers_.end() + != its_data.train_->passengers_.find(its_identifier)) { + must_depart = true; + } else { + // STEP 5: Check whether the current message fits into the current train + if (its_data.train_->buffer_->size() + _size > endpoint_impl<Protocol>::max_message_size_) { + must_depart = true; + } else { + // STEP 6: Check debouncing time + if (its_debouncing > its_data.train_->minimal_max_retention_time_) { + // train's latest departure would already undershot new + // passenger's debounce time + must_depart = true; + } else { + if (its_now + its_debouncing > its_data.train_->departure_) { + // train departs earlier as the new passenger's debounce + // time allows + must_depart = true; + } else { + // STEP 7: Check maximum retention time + if (its_retention < its_data.train_->minimal_debounce_time_) { + // train's earliest departure would already exceed + // the new passenger's retention time. + must_depart = true; + } else { + if (its_now + its_retention < its_data.train_->departure_) { + its_data.train_->departure_ = its_now + its_retention; + } + } + } + } + } + } + } + + // STEP 8: if necessary, send current buffer and create a new one + if (must_depart) { + // STEP 8.1: check if debounce time would be undershot here if the train + // departs. Block sending until train is allowed to depart. + schedule_train(its_data); + + its_data.train_ = std::make_shared<train>(); + its_data.train_->departure_ = its_now + its_retention; + } + + // STEP 9: insert current message buffer + its_data.train_->buffer_->insert(its_data.train_->buffer_->end(), _data, _data + _size); + its_data.train_->passengers_.insert(its_identifier); + // STEP 9.1: update the trains minimal debounce time if necessary + if (its_debouncing < its_data.train_->minimal_debounce_time_) { + its_data.train_->minimal_debounce_time_ = its_debouncing; + } + // STEP 9.2: update the trains minimal maximum retention time if necessary + if (its_retention < its_data.train_->minimal_max_retention_time_) { + its_data.train_->minimal_max_retention_time_ = its_retention; + } + + // STEP 10: restart timer with current departure time + start_dispatch_timer(its_target_iterator, its_now); + + return true; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::tp_segmentation_enabled( + service_t /*_service*/, instance_t /*_instance*/, method_t /*_method*/) const { + + return false; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::send_segments( + const tp::tp_split_messages_t &_segments, std::uint32_t _separation_time, + const endpoint_type &_target) { + + if (_segments.size() == 0) + return; + + const auto its_target_iterator = find_or_create_target_unlocked(_target); + auto &its_data = its_target_iterator->second; + + auto its_now(std::chrono::steady_clock::now()); + + const service_t its_service = bithelper::read_uint16_be(&(*(_segments[0]))[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&(*(_segments[0]))[VSOMEIP_METHOD_POS_MIN]); + + std::chrono::nanoseconds its_debouncing(0), its_retention(0); + if (its_service != VSOMEIP_SD_SERVICE && its_method != VSOMEIP_SD_METHOD) { + get_configured_times_from_endpoint(its_service, its_method, + &its_debouncing, &its_retention); + } + // update the trains minimal debounce time if necessary + if (its_debouncing < its_data.train_->minimal_debounce_time_) { + its_data.train_->minimal_debounce_time_ = its_debouncing; + } + // update the trains minimal maximum retention time if necessary + if (its_retention < its_data.train_->minimal_max_retention_time_) { + its_data.train_->minimal_max_retention_time_ = its_retention; + } + // We only need to respect the debouncing. There is no need to wait for further + // messages as we will send several now anyway. + if (!its_data.train_->passengers_.empty()) { + schedule_train(its_data); + its_data.train_ = std::make_shared<train>(); + its_data.train_->departure_ = its_now + its_retention; + } + + for (const auto &s : _segments) { + its_data.queue_.emplace_back(s, _separation_time); + its_data.queue_size_ += s->size(); + } + + if (!its_data.is_sending_ && !its_data.queue_.empty()) { // no writing in progress + // ignore retention time and send immediately as the train is full anyway + (void)send_queued(its_target_iterator); + } +} + +template<typename Protocol> +typename server_endpoint_impl<Protocol>::target_data_iterator_type +server_endpoint_impl<Protocol>::find_or_create_target_unlocked(endpoint_type _target) { + + auto its_iterator = targets_.find(_target); + if (its_iterator == targets_.end()) { + auto its_result = targets_.emplace( + std::make_pair(_target, endpoint_data_type(this->io_))); + its_iterator = its_result.first; + } + + return its_iterator; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::schedule_train(endpoint_data_type &_data) { + + if (_data.has_last_departure_) { + if (_data.last_departure_ + _data.train_->minimal_debounce_time_ + > _data.train_->departure_) { + _data.train_->departure_ = _data.last_departure_ + + _data.train_->minimal_debounce_time_; + } + } + + _data.dispatched_trains_[_data.train_->departure_] + .push_back(_data.train_); +} + +template<typename Protocol> +typename endpoint_impl<Protocol>::cms_ret_e server_endpoint_impl<Protocol>::check_message_size( + const std::uint8_t * const _data, std::uint32_t _size, + const endpoint_type& _target) { + typename endpoint_impl<Protocol>::cms_ret_e ret(endpoint_impl<Protocol>::cms_ret_e::MSG_OK); + if (endpoint_impl<Protocol>::max_message_size_ != MESSAGE_SIZE_UNLIMITED + && _size > endpoint_impl<Protocol>::max_message_size_) { + if (endpoint_impl<Protocol>::is_supporting_someip_tp_ && _data != nullptr) { + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + instance_t its_instance = this->get_instance(its_service); + + if (its_instance != ANY_INSTANCE) { + if (tp_segmentation_enabled(its_service, its_instance, its_method)) { + std::uint16_t its_max_segment_length; + std::uint32_t its_separation_time; + + this->configuration_->get_tp_configuration( + its_service, its_instance, its_method, false, + its_max_segment_length, its_separation_time); + send_segments(tp::tp::tp_split_message(_data, _size, + its_max_segment_length), its_separation_time, _target); + return endpoint_impl<Protocol>::cms_ret_e::MSG_WAS_SPLIT; + } + } + } + VSOMEIP_ERROR << "sei::send_intern: Dropping to big message (" << _size + << " Bytes). Maximum allowed message size is: " + << endpoint_impl<Protocol>::max_message_size_ << " Bytes."; + ret = endpoint_impl<Protocol>::cms_ret_e::MSG_TOO_BIG; + } + return ret; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::recalculate_queue_size(endpoint_data_type &_data) const { + _data.queue_size_ = 0; + for (const auto &q : _data.queue_) { + if (q.first) { + _data.queue_size_ += q.first->size(); + } + } +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::check_queue_limit(const uint8_t *_data, std::uint32_t _size, + endpoint_data_type &_endpoint_data) const { + + // No queue limit --> Fine + if (endpoint_impl<Protocol>::queue_limit_ == QUEUE_SIZE_UNLIMITED) { + return true; + } + + // Current queue size is bigger than the maximum queue size + if (_endpoint_data.queue_size_ >= endpoint_impl<Protocol>::queue_limit_) { + size_t its_error_queue_size { _endpoint_data.queue_size_ }; + recalculate_queue_size(_endpoint_data); + + VSOMEIP_WARNING << __func__ << ": Detected possible queue size underflow (" + << std::dec << its_error_queue_size << "). Recalculating it (" + << std::dec << _endpoint_data.queue_size_ << ")"; + } + + if (_endpoint_data.queue_size_ + _size > endpoint_impl<Protocol>::queue_limit_ + || _endpoint_data.queue_size_ + _size < _size) { // overflow protection + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_size >= VSOMEIP_SESSION_POS_MAX) { + // this will yield wrong IDs for local communication as the commands + // are prepended to the actual payload + // it will print: + // (lowbyte service ID + highbyte methoid) + // [(Command + lowerbyte sender's client ID). + // highbyte sender's client ID + lowbyte command size. + // lowbyte methodid + highbyte vsomeip length] + its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_ERROR << "sei::send_intern: queue size limit (" << std::dec + << endpoint_impl<Protocol>::queue_limit_ + << ") reached. Dropping message (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_session << "]" + << " queue_size: " << std::dec << _endpoint_data.queue_size_ + << " data size: " << _size; + return false; + } + return true; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::queue_train( + target_data_iterator_type _it, const std::shared_ptr<train> &_train) { + + bool must_erase(false); + + auto &its_data = _it->second; + its_data.queue_size_ += _train->buffer_->size(); + its_data.queue_.emplace_back(_train->buffer_, 0); + + if (!its_data.is_sending_) { // no writing in progress + must_erase = send_queued(_it); + } + + return must_erase; +} + +template<typename Protocol> +bool server_endpoint_impl<Protocol>::flush(endpoint_type _key) { + + bool has_queued(true); + bool is_current_train(true); + + std::lock_guard<std::mutex> its_lock(mutex_); + + auto it = targets_.find(_key); + if (it == targets_.end()) + return false; + + auto &its_data = it->second; + auto its_train(its_data.train_); + if (!its_data.dispatched_trains_.empty()) { + + auto its_dispatched = its_data.dispatched_trains_.begin(); + if (its_dispatched->first <= its_train->departure_) { + + is_current_train = false; + if (!its_dispatched->second.empty()) { + its_train = its_dispatched->second.front(); + its_dispatched->second.pop_front(); + if (its_dispatched->second.empty()) { + + its_data.dispatched_trains_.erase(its_dispatched); + } + } + } + } + + if (!its_train->buffer_->empty()) { + + queue_train(it, its_train); + + // Reset current train if necessary + if (is_current_train) { + its_train->reset(); + } + } else { + has_queued = false; + } + + if (!is_current_train || !its_data.dispatched_trains_.empty()) { + + auto its_now(std::chrono::steady_clock::now()); + start_dispatch_timer(it, its_now); + } + + return has_queued; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::connect_cbk( + boost::system::error_code const &_error) { + (void)_error; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::send_cbk(const endpoint_type _key, + boost::system::error_code const& _error, + std::size_t _bytes) { + (void)_bytes; + // Helper + auto check_if_all_msgs_for_stopped_service_are_sent = [&]() { + bool found_service_msg(false); + service_t its_stopped_service(ANY_SERVICE); + for (auto stp_hndlr_iter = prepare_stop_handlers_.begin(); + stp_hndlr_iter != prepare_stop_handlers_.end();) { + its_stopped_service = stp_hndlr_iter->first; + if (its_stopped_service == ANY_SERVICE) { + ++stp_hndlr_iter; + continue; + } + for (const auto& t : targets_) { + for (const auto& e : t.second.queue_ ) { + const service_t its_service = bithelper::read_uint16_be(&(*e.first)[VSOMEIP_SERVICE_POS_MIN]); + if (its_service == its_stopped_service) { + found_service_msg = true; + break; + } + } + if (found_service_msg) { + break; + } + } + if (found_service_msg) { + ++stp_hndlr_iter; + } else { // all messages of the to be stopped service have been sent + auto handler = stp_hndlr_iter->second; + auto ptr = this->shared_from_this(); + endpoint_impl<Protocol>::io_.post([ptr, handler]() { handler(ptr); }); + stp_hndlr_iter = prepare_stop_handlers_.erase(stp_hndlr_iter); + } + } + }; + + auto check_if_all_queues_are_empty = [&](){ + if (prepare_stop_handlers_.size() > 1) { + // before the endpoint was stopped completely other + // prepare_stop_handlers have been queued ensure to call them as well + check_if_all_msgs_for_stopped_service_are_sent(); + } + if (std::all_of(targets_.begin(), targets_.end(), + [&](const typename target_data_type::value_type &_t) + { return _t.second.queue_.empty(); })) { + // all outstanding response have been sent. + auto found_cbk = prepare_stop_handlers_.find(ANY_SERVICE); + if (found_cbk != prepare_stop_handlers_.end()) { + auto handler = found_cbk->second; + auto ptr = this->shared_from_this(); + endpoint_impl<Protocol>::io_.post([ptr, handler]() { handler(ptr); }); + prepare_stop_handlers_.erase(found_cbk); + } + } + }; + + std::lock_guard<std::mutex> its_lock(mutex_); + + auto it = targets_.find(_key); + if (it == targets_.end()) + return; + + auto& its_data = it->second; + + boost::system::error_code ec; + its_data.sent_timer_.cancel(ec); + + // Extracts some information for logging puposes. + // + // TODO(brunoldsilva): Code like this is used in a lot of places. It might be worth moving this + // into a proper function. + auto parse_message_ids = [] ( + const message_buffer_ptr_t& buffer, + service_t& its_service, + method_t& its_method, + client_t& its_client, + session_t& its_session + ) { + if (buffer && buffer->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*buffer)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*buffer)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*buffer)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*buffer)[VSOMEIP_SESSION_POS_MIN]); + } + }; + + + message_buffer_ptr_t its_buffer; + if (its_data.queue_.size()) { + its_buffer = its_data.queue_.front().first; + } + + if (!its_buffer) { + // Pointer not initialized. + its_buffer = std::make_shared<message_buffer_t>(); + VSOMEIP_WARNING << __func__ << ": prevented nullptr de-reference by initializing queue buffer"; + } + + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + + if (!_error) { + const std::size_t payload_size = its_buffer->size(); + if (payload_size <= its_data.queue_size_) { + its_data.queue_size_ -= payload_size; + its_data.queue_.pop_front(); + } else { + parse_message_ids(its_buffer, its_service, its_method, its_client, its_session); + VSOMEIP_WARNING << __func__ << ": prevented queue_size underflow. queue_size: " + << its_data.queue_size_ << " payload_size: " << payload_size << " payload: (" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "]"; + its_data.queue_.pop_front(); + recalculate_queue_size(its_data); + } + + update_last_departure(its_data); + + if (!prepare_stop_handlers_.empty() && !endpoint_impl<Protocol>::sending_blocked_) { + // only one service instance is stopped + check_if_all_msgs_for_stopped_service_are_sent(); + } + + if (!its_data.queue_.empty()) { + (void)send_queued(it); + } else { + if (!prepare_stop_handlers_.empty() && endpoint_impl<Protocol>::sending_blocked_) { + // endpoint is shutting down completely + cancel_dispatch_timer(it); + targets_.erase(it); + check_if_all_queues_are_empty(); + } else + its_data.is_sending_ = false; + } + } else { + // error: sending of outstanding responses isn't started again + // delete remaining outstanding responses + parse_message_ids(its_buffer, its_service, its_method, its_client, its_session); + VSOMEIP_WARNING << "sei::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information(it) << " " + << std::dec << its_data.queue_.size() << " " + << its_data.queue_size_ << " (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_session << "]"; + cancel_dispatch_timer(it); + targets_.erase(it); + if (!prepare_stop_handlers_.empty()) { + if (endpoint_impl<Protocol>::sending_blocked_) { + // endpoint is shutting down completely, ensure to call + // prepare_stop_handlers even in error cases + check_if_all_queues_are_empty(); + } else { + // only one service instance is stopped + check_if_all_msgs_for_stopped_service_are_sent(); + } + } + } +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::flush_cbk( + endpoint_type _key, + const boost::system::error_code &_error_code) { + + if (!_error_code) { + + (void) flush(_key); + } +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::remove_stop_handler(service_t _service) { + std::stringstream its_services_log; + its_services_log << __func__ << ": "; + + std::lock_guard<std::mutex> its_lock{mutex_}; + for (const auto &its_service : prepare_stop_handlers_) + its_services_log << std::hex << std::setw(4) << std::setfill('0') << its_service.first << ' '; + + VSOMEIP_INFO << its_services_log.str(); + prepare_stop_handlers_.erase(_service); +} + +template<typename Protocol> +size_t server_endpoint_impl<Protocol>::get_queue_size() const { + size_t its_queue_size(0); + { + std::lock_guard<std::mutex> its_lock(mutex_); + for (const auto &t : targets_) { + its_queue_size += t.second.queue_size_; + } + } + return its_queue_size; +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::start_dispatch_timer( + target_data_iterator_type _it, + const std::chrono::steady_clock::time_point &_now) { + + auto &its_data = _it->second; + std::shared_ptr<train> its_train(its_data.train_); + + if (!its_data.dispatched_trains_.empty()) { + + auto its_dispatched = its_data.dispatched_trains_.begin(); + if (its_dispatched->first < its_train->departure_) { + + its_train = its_dispatched->second.front(); + } + } + + std::chrono::nanoseconds its_offset; + if (its_train->departure_ > _now) { + + its_offset = std::chrono::duration_cast<std::chrono::nanoseconds>( + its_train->departure_ - _now); + } else { // already departure time + + its_offset = std::chrono::nanoseconds::zero(); + } + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + its_data.dispatch_timer_->expires_from_now(its_offset); +#else + its_data.dispatch_timer_->expires_from_now( + std::chrono::duration_cast< + std::chrono::steady_clock::duration>(its_offset)); +#endif + its_data.dispatch_timer_->async_wait( + std::bind(&server_endpoint_impl<Protocol>::flush_cbk, + this->shared_from_this(), _it->first, std::placeholders::_1)); +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::cancel_dispatch_timer( + target_data_iterator_type _it) { + + boost::system::error_code ec; + _it->second.dispatch_timer_->cancel(ec); +} + +template<typename Protocol> +void server_endpoint_impl<Protocol>::update_last_departure( + endpoint_data_type &_data) { + + _data.last_departure_ = std::chrono::steady_clock::now(); + _data.has_last_departure_ = true; +} + +// Instantiate template +#if defined(__linux__) || defined(__QNX__) +template class server_endpoint_impl<boost::asio::local::stream_protocol>; +#endif + +template class server_endpoint_impl<boost::asio::ip::tcp>; +template class server_endpoint_impl<boost::asio::ip::udp>; + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_client_endpoint_impl.cpp new file mode 100644 index 00000000000..124c78b70fd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -0,0 +1,1039 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <iomanip> + +#include <boost/asio/write.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_host.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../include/tcp_client_endpoint_impl.hpp" +#include "../../utility/include/utility.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +tcp_client_endpoint_impl::tcp_client_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, + const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) + : tcp_client_endpoint_base_impl(_endpoint_host, _routing_host, _local, _remote, _io, + _configuration), + recv_buffer_size_initial_(VSOMEIP_SOMEIP_HEADER_SIZE), + recv_buffer_(std::make_shared<message_buffer_t>(recv_buffer_size_initial_, 0)), + shrink_count_(0), + buffer_shrink_threshold_(configuration_->get_buffer_shrink_threshold()), + remote_address_(_remote.address()), + remote_port_(_remote.port()), + last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)), + // send timeout after 2/3 of configured ttl, warning after 1/3 + send_timeout_(configuration_->get_sd_ttl() * 666), + send_timeout_warning_(send_timeout_ / 2), + tcp_restart_aborts_max_(configuration_->get_max_tcp_restart_aborts()), + tcp_connect_time_max_(configuration_->get_max_tcp_connect_time()), + aborted_restart_count_(0), + sent_timer_(_io) { + + is_supporting_magic_cookies_ = true; + + this->max_message_size_ = _configuration->get_max_message_size_reliable( + _remote.address().to_string(), + _remote.port()); + this->queue_limit_ = _configuration->get_endpoint_queue_limit(_remote.address().to_string(), + _remote.port()); +} + +tcp_client_endpoint_impl::~tcp_client_endpoint_impl() { + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + its_host->release_port(local_.port(), true); + } +} + +bool tcp_client_endpoint_impl::is_local() const { + return false; +} + +void tcp_client_endpoint_impl::start() { + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); +} + +void tcp_client_endpoint_impl::restart(bool _force) { + auto self = std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()); + auto restart_func = [self, _force] { + if (!_force && self->state_ == cei_state_e::CONNECTING) { + std::chrono::steady_clock::time_point its_current + = std::chrono::steady_clock::now(); + std::int64_t its_connect_duration = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - self->connect_timepoint_).count(); + if (self->aborted_restart_count_ < self->tcp_restart_aborts_max_ + && its_connect_duration < self->tcp_connect_time_max_) { + self->aborted_restart_count_++; + return; + } else { + VSOMEIP_WARNING << "tce::restart: maximum number of aborted restarts [" + << self->tcp_restart_aborts_max_ << "] reached! its_connect_duration: " + << its_connect_duration; + } + } + self->state_ = cei_state_e::CONNECTING; + std::string address_port_local; + { + std::lock_guard<std::mutex> its_lock(self->socket_mutex_); + address_port_local = self->get_address_port_local(); + self->shutdown_and_close_socket_unlocked(true); + self->recv_buffer_ = std::make_shared<message_buffer_t>(self->recv_buffer_size_initial_, 0); + } + self->was_not_connected_ = true; + self->reconnect_counter_ = 0; + { + std::lock_guard<std::recursive_mutex> its_lock(self->mutex_); + for (const auto &q : self->queue_) { + const service_t its_service = bithelper::read_uint16_be(&(*q.first)[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&(*q.first)[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&(*q.first)[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&(*q.first)[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_WARNING << "tce::restart: dropping message: " + << "remote:" << self->get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_session << "]" + << " size: " << std::dec << q.first->size(); + } + self->queue_.clear(); + self->queue_size_ = 0; + } + VSOMEIP_WARNING << "tce::restart: local: " << address_port_local + << " remote: " << self->get_address_port_remote(); + self->start_connect_timer(); + }; + // bind to strand_ to avoid socket closure if + // parallel socket operation is currently active + strand_.dispatch(restart_func); +} + +void tcp_client_endpoint_impl::connect() { + start_connecting_timer(); + std::unique_lock<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + socket_->open(remote_.protocol(), its_error); + + if (!its_error || its_error == boost::asio::error::already_open) { + // Nagle algorithm off + socket_->set_option(boost::asio::ip::tcp::no_delay(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: couldn't disable " + << "Nagle algorithm: " << its_error.message() + << " remote:" << get_address_port_remote(); + } + + socket_->set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: couldn't enable " + << "keep_alive: " << its_error.message() + << " remote:" << get_address_port_remote(); + } + + // Enable SO_REUSEADDR to avoid bind problems with services going offline + // and coming online again and the user has specified only a small number + // of ports in the clients section for one service instance + socket_->set_option(boost::asio::socket_base::reuse_address(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: couldn't enable " + << "SO_REUSEADDR: " << its_error.message() + << " remote:" << get_address_port_remote(); + } + socket_->set_option(boost::asio::socket_base::linger(true, 0), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: couldn't enable " + << "SO_LINGER: " << its_error.message() + << " remote:" << get_address_port_remote(); + } + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // If specified, bind to device + std::string its_device(configuration_->get_device()); + if (its_device != "") { + if (setsockopt(socket_->native_handle(), + SOL_SOCKET, SO_BINDTODEVICE, its_device.c_str(), static_cast<socklen_t>(its_device.size())) == -1) { + VSOMEIP_WARNING << "TCP Client: Could not bind to device \"" << its_device << "\""; + } + } +#endif + + // In case a client endpoint port was configured, + // bind to it before connecting + if (local_.port() != ILLEGAL_PORT) { + boost::system::error_code its_bind_error; + socket_->bind(local_, its_bind_error); + if(its_bind_error) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: " + "Error binding socket: " << its_bind_error.message() + << " local: " << get_address_port_local() + << " remote:" << get_address_port_remote(); + + its_lock.unlock(); + + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + // set new client port depending on service / instance / remote port + if (!its_host->on_bind_error(shared_from_this(), remote_address_, remote_port_)) { + VSOMEIP_WARNING << "tcp_client_endpoint::connect: " + "Failed to set new local port for tce: " + << " local: " << local_.address().to_string() + << ":" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } else { + VSOMEIP_INFO << "tcp_client_endpoint::connect: " + "Using new new local port for tce: " + << " local: " << local_.address().to_string() + << ":" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } + } + std::size_t operations_cancelled; + { + std::lock_guard<std::mutex> its_lock(connecting_timer_mutex_); + operations_cancelled = connecting_timer_.cancel(); + } + if (operations_cancelled != 0) { + try { + VSOMEIP_WARNING + << "tce::" << __func__ + << ":connecting to: local:" << this->get_address_port_local() + << " remote: " << this->get_address_port_remote(); + // don't connect on bind error to avoid using a random port + strand_.post(std::bind(&client_endpoint_impl::connect_cbk, + shared_from_this(), its_bind_error)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "tcp_client_endpoint_impl::connect: " + << e.what() + << " local: " << get_address_port_local() + << " remote:" << get_address_port_remote(); + } + } + return; + } + } + state_ = cei_state_e::CONNECTING; + connect_timepoint_ = std::chrono::steady_clock::now(); + aborted_restart_count_ = 0; + VSOMEIP_WARNING << "tce::" << __func__ + << ":connecting to: local:" << this->get_address_port_local() + << " remote: " << this->get_address_port_remote(); + socket_->async_connect( + remote_, + strand_.wrap( + std::bind( + &tcp_client_endpoint_base_impl::cancel_and_connect_cbk, + shared_from_this(), + std::placeholders::_1 + ) + ) + ); + } else { + VSOMEIP_WARNING << "tce::" << __func__ << ": could not connect " + << "(" << its_error.value() << "): " << its_error.message(); + std::size_t operations_cancelled; + { + std::lock_guard<std::mutex> its_lock(connecting_timer_mutex_); + operations_cancelled = connecting_timer_.cancel(); + } + if (operations_cancelled != 0) { + VSOMEIP_WARNING << "tce::" << __func__ << "Error opening socket: (" << its_error.message() + << "): conneting to local:" << this->get_address_port_local() + << " remote: " << this->get_address_port_remote(); + strand_.post(std::bind(&tcp_client_endpoint_base_impl::connect_cbk, + shared_from_this(), its_error)); + } + } +} + +void tcp_client_endpoint_impl::receive() { + message_buffer_ptr_t its_recv_buffer; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + its_recv_buffer = recv_buffer_; + } + auto self = std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()); + strand_.dispatch([self, &its_recv_buffer](){ + self->receive(its_recv_buffer, 0, 0); + }); +} + +void tcp_client_endpoint_impl::receive(message_buffer_ptr_t _recv_buffer, + std::size_t _recv_buffer_size, + std::size_t _missing_capacity) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if(socket_->is_open()) { + const std::size_t its_capacity(_recv_buffer->capacity()); + size_t buffer_size = its_capacity - _recv_buffer_size; + try { + if (_missing_capacity) { + if (_missing_capacity > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!"; + return; + } + const std::size_t its_required_capacity(_recv_buffer_size + _missing_capacity); + if (its_capacity < its_required_capacity) { + _recv_buffer->reserve(its_required_capacity); + _recv_buffer->resize(its_required_capacity, 0x0); + if (_recv_buffer->size() > 1048576) { + VSOMEIP_INFO << "tce: recv_buffer size is: " << + _recv_buffer->size() + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + } + buffer_size = _missing_capacity; + } else if (buffer_shrink_threshold_ + && shrink_count_ > buffer_shrink_threshold_ + && _recv_buffer_size == 0) { + _recv_buffer->resize(recv_buffer_size_initial_, 0x0); + _recv_buffer->shrink_to_fit(); + buffer_size = recv_buffer_size_initial_; + shrink_count_ = 0; + } + } catch (const std::exception &e) { + handle_recv_buffer_exception(e, _recv_buffer, _recv_buffer_size); + // don't start receiving again + return; + } + socket_->async_receive( + boost::asio::buffer(&(*_recv_buffer)[_recv_buffer_size], buffer_size), + strand_.wrap( + std::bind( + &tcp_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + _recv_buffer, + _recv_buffer_size + ) + ) + ); + } +} + +void tcp_client_endpoint_impl::send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry) { + const service_t its_service = bithelper::read_uint16_be(&(*_entry.first)[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&(*_entry.first)[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&(*_entry.first)[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&(*_entry.first)[VSOMEIP_SESSION_POS_MIN]); + if (has_enabled_magic_cookies_) { + const std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + if (std::chrono::duration_cast<std::chrono::milliseconds>( + now - last_cookie_sent_) > std::chrono::milliseconds(10000)) { + send_magic_cookie(_entry.first); + last_cookie_sent_ = now; + } + } + + +#if 0 + std::stringstream msg; + msg << "tcei<" << remote_.address() << ":" + << std::dec << remote_.port() << ">::sq: "; + for (std::size_t i = 0; i < _buffer->size(); i++) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int)(*_entry.first)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + boost::asio::async_write( + *socket_, + boost::asio::buffer(*_entry.first), + std::bind( + &tcp_client_endpoint_impl::write_completion_condition, + std::static_pointer_cast<tcp_client_endpoint_impl>(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + _entry.first->size(), + its_service, its_method, its_client, its_session, + std::chrono::steady_clock::now()), + strand_.wrap( + std::bind( + &tcp_client_endpoint_base_impl::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + _entry.first + )) + ); + } + } +} + +void tcp_client_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + configuration_->get_configured_timing_requests(_service, + remote_address_.to_string(), remote_port_, _method, + _debouncing, _maximum_retention); +} + +bool tcp_client_endpoint_impl::get_remote_address( + boost::asio::ip::address &_address) const { + if (remote_address_.is_unspecified()) { + return false; + } + _address = remote_address_; + return true; +} + +uint16_t tcp_client_endpoint_impl::get_local_port() const { + + uint16_t its_port(0); + + // Local port may be zero, if no client ports are configured + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + boost::system::error_code its_error; + endpoint_type its_local = socket_->local_endpoint(its_error); + if (!its_error) { + its_port = its_local.port(); + return its_port; + } else { + VSOMEIP_WARNING << "tce::" << __func__ << ": couldn't get local endpoint port " + << "(" << its_error.value() << "): " << its_error.message(); + } + } + + return local_.port(); +} + +void tcp_client_endpoint_impl::set_local_port() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + if (socket_->is_open()) { + endpoint_type its_endpoint = socket_->local_endpoint(its_error); + if (!its_error) { + local_.port(its_endpoint.port()); + } else { + VSOMEIP_WARNING << "tcp_client_endpoint_impl::set_local_port() " + << " couldn't get local_endpoint: " << its_error.message(); + } + } else { + VSOMEIP_WARNING << "tcp_client_endpoint_impl::set_local_port() " + << "failed to set port because the socket is not opened"; + } +} + +void tcp_client_endpoint_impl::set_local_port(port_t _port) { + + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (!socket_->is_open()) { + local_.port(_port); + } else { + boost::system::error_code its_error; + endpoint_type its_endpoint = socket_->local_endpoint(its_error); + if (!its_error) + local_.port(its_endpoint.port()); + VSOMEIP_ERROR << "tcp_client_endpoint_impl::set_local_port() " + << "Cannot change port on open socket!"; + } +} + +std::size_t tcp_client_endpoint_impl::write_completion_condition( + const boost::system::error_code& _error, std::size_t _bytes_transferred, + std::size_t _bytes_to_send, service_t _service, method_t _method, + client_t _client, session_t _session, + const std::chrono::steady_clock::time_point _start) { + + if (_error) { + VSOMEIP_ERROR << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + return 0; + } + + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::milliseconds passed = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start); + if (passed > send_timeout_warning_) { + if (passed > send_timeout_) { + VSOMEIP_ERROR << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + } else { + VSOMEIP_WARNING << "tce::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_warning_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + } + } + return _bytes_to_send - _bytes_transferred; +} + +std::uint16_t tcp_client_endpoint_impl::get_remote_port() const { + return remote_port_; +} + +bool tcp_client_endpoint_impl::is_reliable() const { + return true; +} + +bool tcp_client_endpoint_impl::is_magic_cookie(const message_buffer_ptr_t& _recv_buffer, + size_t _offset) const { + return (0 == std::memcmp(SERVICE_COOKIE, &(*_recv_buffer)[_offset], sizeof(SERVICE_COOKIE))); +} + +void tcp_client_endpoint_impl::send_magic_cookie(message_buffer_ptr_t &_buffer) { + if (max_message_size_ == MESSAGE_SIZE_UNLIMITED + || max_message_size_ - _buffer->size() >= + VSOMEIP_SOMEIP_HEADER_SIZE + VSOMEIP_SOMEIP_MAGIC_COOKIE_SIZE) { + _buffer->insert( + _buffer->begin(), + CLIENT_COOKIE, + CLIENT_COOKIE + sizeof(CLIENT_COOKIE) + ); + queue_size_ += sizeof(CLIENT_COOKIE); + } else { + VSOMEIP_WARNING << "Packet full. Cannot insert magic cookie!"; + } +} + +void tcp_client_endpoint_impl::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes, + const message_buffer_ptr_t& _recv_buffer, std::size_t _recv_buffer_size) { + if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + return; + } +#if 0 + std::stringstream msg; + msg << "cei::rcb (" << _error.message() << "): "; + for (std::size_t i = 0; i < _bytes + _recv_buffer_size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int) (_recv_buffer)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::unique_lock<std::mutex> its_lock(socket_mutex_); + std::shared_ptr<routing_host> its_host = routing_host_.lock(); + if (its_host) { + std::uint32_t its_missing_capacity(0); + if (!_error && 0 < _bytes) { + if (_recv_buffer_size + _bytes > _recv_buffer->size()) { + VSOMEIP_ERROR << "receive buffer overflow in tcp client endpoint ~> abort!"; + return; + } + _recv_buffer_size += _bytes; + + size_t its_iteration_gap = 0; + bool has_full_message(false); + do { + uint64_t read_message_size + = utility::get_message_size(&(*_recv_buffer)[its_iteration_gap], + _recv_buffer_size); + if (read_message_size > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Message size exceeds allowed maximum!"; + return; + } + uint32_t current_message_size = static_cast<uint32_t>(read_message_size); + has_full_message = (current_message_size > VSOMEIP_RETURN_CODE_POS + && current_message_size <= _recv_buffer_size); + if (has_full_message) { + bool needs_forwarding(true); + if (is_magic_cookie(_recv_buffer, its_iteration_gap)) { + has_enabled_magic_cookies_ = true; + } else { + if (has_enabled_magic_cookies_) { + uint32_t its_offset = find_magic_cookie(&(*_recv_buffer)[its_iteration_gap], + (uint32_t) _recv_buffer_size); + if (its_offset < current_message_size) { + VSOMEIP_ERROR << "Message includes Magic Cookie. Ignoring it."; + current_message_size = its_offset; + needs_forwarding = false; + } + } + } + if (needs_forwarding) { + if (!has_enabled_magic_cookies_) { + its_lock.unlock(); + its_host->on_message(&(*_recv_buffer)[its_iteration_gap], + current_message_size, this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + its_lock.lock(); + } else { + // Only call on_message without a magic cookie in front of the buffer! + if (!is_magic_cookie(_recv_buffer, its_iteration_gap)) { + its_lock.unlock(); + its_host->on_message(&(*_recv_buffer)[its_iteration_gap], + current_message_size, this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + its_lock.lock(); + } + } + } + calculate_shrink_count(_recv_buffer, _recv_buffer_size); + _recv_buffer_size -= current_message_size; + its_iteration_gap += current_message_size; + its_missing_capacity = 0; + } else if (has_enabled_magic_cookies_ && _recv_buffer_size > 0) { + const uint32_t its_offset = find_magic_cookie( + &(*_recv_buffer)[its_iteration_gap], _recv_buffer_size); + if (its_offset < _recv_buffer_size) { + _recv_buffer_size -= its_offset; + its_iteration_gap += its_offset; + has_full_message = true; // trigger next loop + VSOMEIP_ERROR << "Detected Magic Cookie within message data." + << " Resyncing. local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + } + + if (!has_full_message) { + if (_recv_buffer_size > VSOMEIP_RETURN_CODE_POS) { + bool invalid_parameter_detected { false }; + if (recv_buffer_->size() <= (its_iteration_gap + VSOMEIP_RETURN_CODE_POS)) { + VSOMEIP_ERROR << "TCP Client receive_cbk is trying to access invalid vector position." + << " Actual: " << recv_buffer_->size() + << " Received: " << _recv_buffer->size() + << " Current: " << current_message_size + << " Indicated: " << _recv_buffer_size + << " Bytes: " << _bytes + << " Iteration_gap: " << its_iteration_gap + << " Is_full_message: " << has_full_message; + return; + } else if ((*recv_buffer_)[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + invalid_parameter_detected = true; + VSOMEIP_ERROR << "tce: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + // ensure to send back a message w/ wrong protocol version + its_lock.unlock(); + its_host->on_message(&(*_recv_buffer)[its_iteration_gap], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + its_lock.lock(); + } else if (!utility::is_valid_message_type(static_cast<message_type_e>( + (*recv_buffer_)[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]))) { + invalid_parameter_detected = true; + VSOMEIP_ERROR << "tce: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + (*recv_buffer_)[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]))) { + invalid_parameter_detected = true; + VSOMEIP_ERROR << "tce: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*recv_buffer_)[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + + if (invalid_parameter_detected) { + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket_unlocked(false); + its_lock.unlock(); + + // wait_until_sent interprets "no error" as timeout. + // Therefore call it with an error. + wait_until_sent(boost::asio::error::operation_aborted); + return; + } + } + if (max_message_size_ != MESSAGE_SIZE_UNLIMITED && + current_message_size > max_message_size_) { + _recv_buffer_size = 0; + _recv_buffer->resize(recv_buffer_size_initial_, 0x0); + _recv_buffer->shrink_to_fit(); + if (has_enabled_magic_cookies_) { + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << "). Magic Cookies are enabled: " + << "Resetting receiver. local: " + << get_address_port_local() << " remote: " + << get_address_port_remote(); + } else { + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << ") Magic cookies are disabled, " + << "Restarting connection. " + << "local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket_unlocked(false); + its_lock.unlock(); + + // wait_until_sent interprets "no error" as timeout. + // Therefore call it with an error. + wait_until_sent(boost::asio::error::operation_aborted); + return; + } + } else if (current_message_size > _recv_buffer_size) { + its_missing_capacity = current_message_size + - static_cast<std::uint32_t>(_recv_buffer_size); + } else if (VSOMEIP_SOMEIP_HEADER_SIZE > _recv_buffer_size) { + its_missing_capacity = VSOMEIP_SOMEIP_HEADER_SIZE + - static_cast<std::uint32_t>(_recv_buffer_size); + } else if (has_enabled_magic_cookies_ && _recv_buffer_size > 0) { + // no need to check for magic cookie here again: has_full_message + // would have been set to true if there was one present in the data + _recv_buffer_size = 0; + _recv_buffer->resize(recv_buffer_size_initial_, 0x0); + _recv_buffer->shrink_to_fit(); + its_missing_capacity = 0; + VSOMEIP_ERROR << "tce::c<" << this + << ">rcb: recv_buffer_capacity: " + << _recv_buffer->capacity() + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Didn't find magic cookie in broken data, trying to resync."; + } else { + VSOMEIP_ERROR << "tce::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << _recv_buffer_size << " but couldn't read " + "out message_size. recv_buffer_capacity: " + << _recv_buffer->capacity() + << " its_iteration_gap: " << its_iteration_gap + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Restarting connection due to missing/broken data TCP stream."; + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket_unlocked(false); + its_lock.unlock(); + + // wait_until_sent interprets "no error" as timeout. + // Therefore call it with an error. + wait_until_sent(boost::asio::error::operation_aborted); + return; + } + } + } while (has_full_message && _recv_buffer_size); + if (its_iteration_gap) { + // Copy incomplete message to front for next receive_cbk iteration + for (size_t i = 0; i < _recv_buffer_size; ++i) { + (*_recv_buffer)[i] = (*_recv_buffer)[i + its_iteration_gap]; + } + // Still more capacity needed after shifting everything to front? + if (its_missing_capacity && + its_missing_capacity <= _recv_buffer->capacity() - _recv_buffer_size) { + its_missing_capacity = 0; + } + } + its_lock.unlock(); + auto self = std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()); + strand_.dispatch([self, &_recv_buffer, _recv_buffer_size, its_missing_capacity](){ + self->receive(_recv_buffer, _recv_buffer_size, its_missing_capacity); + }); + } else { + VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk: " + << _error.message() << "(" << std::dec << _error.value() + << ") local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + if (_error == boost::asio::error::eof || + _error == boost::asio::error::timed_out || + _error == boost::asio::error::bad_descriptor || + _error == boost::asio::error::connection_reset) { + if (state_ == cei_state_e::CONNECTING) { + VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk already" + " restarting" << get_remote_information(); + } else { + VSOMEIP_WARNING << "tcp_client_endpoint receive_cbk restarting."; + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket_unlocked(false); + its_lock.unlock(); + + // wait_until_sent interprets "no error" as timeout. + // Therefore call it with an error. + wait_until_sent(boost::asio::error::operation_aborted); + } + } else { + its_lock.unlock(); + auto self = std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()); + strand_.dispatch([self, &_recv_buffer, _recv_buffer_size, its_missing_capacity](){ + self->receive(_recv_buffer, _recv_buffer_size, its_missing_capacity); + }); + } + } + } +} + +void tcp_client_endpoint_impl::calculate_shrink_count(const message_buffer_ptr_t& _recv_buffer, + std::size_t _recv_buffer_size) { + if (buffer_shrink_threshold_) { + if (_recv_buffer->capacity() != recv_buffer_size_initial_) { + if (_recv_buffer_size < (_recv_buffer->capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + } +} + + +std::string tcp_client_endpoint_impl::get_address_port_remote() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::asio::ip::address its_address; + if (get_remote_address(its_address)) { + its_address_port += its_address.to_string(); + } + its_address_port += ":"; + its_address_port += std::to_string(remote_port_); + return its_address_port; +} + +std::string tcp_client_endpoint_impl::get_address_port_local() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + if (socket_->is_open()) { + endpoint_type its_local_endpoint = socket_->local_endpoint(ec); + if (!ec) { + its_address_port += its_local_endpoint.address().to_string(ec); + its_address_port += ":"; + its_address_port.append(std::to_string(its_local_endpoint.port())); + } else { + VSOMEIP_WARNING << "tce" << __func__ << "coudn't get local endpoint: (" << ec.value() + << "): " << ec.message(); + } + } + return its_address_port; +} + +void tcp_client_endpoint_impl::handle_recv_buffer_exception( + const std::exception &_e, + const message_buffer_ptr_t& _recv_buffer, + std::size_t _recv_buffer_size) { + + std::stringstream its_message; + its_message << "tcp_client_endpoint_impl::connection catched exception" + << _e.what() << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << " shutting down connection. Start of buffer: " + << std::setfill('0') << std::hex; + + for (std::size_t i = 0; i < _recv_buffer_size && i < 16; i++) { + its_message << std::setw(2) << (int) ((*_recv_buffer)[i]) << " "; + } + + its_message << " Last 16 Bytes captured: "; + for (int i = 15; _recv_buffer_size > 15 && i >= 0; i--) { + its_message << std::setw(2) << (int) ((*_recv_buffer)[static_cast<size_t>(i)]) << " "; + } + VSOMEIP_ERROR << its_message.str(); + _recv_buffer->clear(); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + sending_blocked_ = true; + } + { + std::lock_guard<std::mutex> its_lock(connect_timer_mutex_); + boost::system::error_code ec; + connect_timer_.cancel(ec); + } + if (socket_->is_open()) { + boost::system::error_code its_error; + socket_->shutdown(socket_type::shutdown_both, its_error); + if (its_error) { + VSOMEIP_WARNING << "tce::" << __func__ << ": socket shutdown error " + << "(" << its_error.value() << "): " << its_error.message(); + } + socket_->close(its_error); + if (its_error) { + VSOMEIP_WARNING << "tce::" << __func__ << ": socket close error " + << "(" << its_error.value() << "): " << its_error.message(); + } + } +} + +void tcp_client_endpoint_impl::print_status() { + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + std::size_t its_receive_buffer_capacity(0); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + its_queue_size = queue_.size(); + its_data_size = queue_size_; + } + std::string local; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + local = get_address_port_local(); + its_receive_buffer_capacity = recv_buffer_->capacity(); + } + + VSOMEIP_INFO << "status tce: " << local << " -> " + << get_address_port_remote() + << " queue: " << std::dec << its_queue_size + << " data: " << std::dec << its_data_size + << " recv_buffer: " << std::dec << its_receive_buffer_capacity; +} + +std::string tcp_client_endpoint_impl::get_remote_information() const { + boost::system::error_code ec; + return remote_.address().to_string(ec) + ":" + + std::to_string(remote_.port()); +} + +void tcp_client_endpoint_impl::send_cbk(boost::system::error_code const &_error, + std::size_t _bytes, + const message_buffer_ptr_t& _sent_msg) { + (void)_bytes; + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + boost::system::error_code ec; + sent_timer_.cancel(ec); + + if (!_error) { + if (queue_.size() > 0) { + queue_size_ -= queue_.front().first->size(); + queue_.pop_front(); + + update_last_departure(); + + if (queue_.empty()) + is_sending_ = false; + else { + auto its_entry = get_front(); + if (its_entry.first) { + auto self = std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()); + strand_.dispatch( + [self, &its_entry]() { self->send_queued(its_entry);} + ); + } + } + } + return; + } else { + is_sending_ = false; + + if (_error == boost::system::errc::destination_address_required) { + VSOMEIP_WARNING << "tce::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information(); + was_not_connected_ = true; + } else if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + shutdown_and_close_socket(false); + } else { + if (state_ == cei_state_e::CONNECTING) { + VSOMEIP_WARNING << "tce::send_cbk endpoint is already restarting:" + << get_remote_information(); + } else { + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket(false); + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + its_host->on_disconnect(shared_from_this()); + } + restart(true); + } + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_sent_msg && _sent_msg->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_WARNING << "tce::send_cbk received error: " + << _error.message() << " (" << std::dec + << _error.value() << ") " << get_remote_information() + << " " << std::dec << queue_.size() + << " " << std::dec << queue_size_ << " (" + << std::hex << std::setw(4) << std::setfill('0') << its_client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << its_service << "." + << std::hex << std::setw(4) << std::setfill('0') << its_method << "." + << std::hex << std::setw(4) << std::setfill('0') << its_session << "]"; + } + } +} + +std::uint32_t tcp_client_endpoint_impl::get_max_allowed_reconnects() const { + return MAX_RECONNECTS_UNLIMITED; +} + +void tcp_client_endpoint_impl::max_allowed_reconnects_reached() { + return; +} + +void tcp_client_endpoint_impl::wait_until_sent(const boost::system::error_code &_error) { + if (_error && _error != boost::asio::error::operation_aborted) { + // This Function is usually called with boost::asio::error::operation_aborted + // and therefore its part of its normal execution path. + VSOMEIP_WARNING << "tce::" << __func__ << ":: (" << _error.value() + << ") message: " << _error.message(); + } + std::unique_lock<std::recursive_mutex> its_lock(mutex_); + if (!is_sending_ || !_error) { + its_lock.unlock(); + if (!_error) + VSOMEIP_WARNING << __func__ + << ": Maximum wait time for send operation exceeded for tce."; + + std::shared_ptr<endpoint_host> its_ep_host = endpoint_host_.lock(); + its_ep_host->on_disconnect(shared_from_this()); + restart(true); + } else { + std::chrono::milliseconds its_timeout(VSOMEIP_MAX_TCP_SENT_WAIT_TIME); + boost::system::error_code ec; + sent_timer_.expires_from_now(its_timeout, ec); + sent_timer_.async_wait(std::bind(&tcp_client_endpoint_impl::wait_until_sent, + std::dynamic_pointer_cast<tcp_client_endpoint_impl>(shared_from_this()), + std::placeholders::_1)); + } +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_server_endpoint_impl.cpp new file mode 100644 index 00000000000..fa4639d0de5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -0,0 +1,1048 @@ + +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <boost/asio/write.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_definition.hpp" +#include "../include/endpoint_host.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../include/tcp_server_endpoint_impl.hpp" +#include "../../utility/include/utility.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace ip = boost::asio::ip; + +namespace vsomeip_v3 { + +tcp_server_endpoint_impl::tcp_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) + : tcp_server_endpoint_base_impl(_endpoint_host, _routing_host, _io, _configuration), + acceptor_(_io), + buffer_shrink_threshold_(configuration_->get_buffer_shrink_threshold()), + // send timeout after 2/3 of configured ttl, warning after 1/3 + send_timeout_(configuration_->get_sd_ttl() * 666) { + is_supporting_magic_cookies_ = true; +} + +bool tcp_server_endpoint_impl::is_local() const { + return false; +} + +void tcp_server_endpoint_impl::init(const endpoint_type& _local, + boost::system::error_code& _error) { + acceptor_.open(_local.protocol(), _error); + if (_error) + return; + + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), _error); + if (_error) + return; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // If specified, bind to device + std::string its_device(configuration_->get_device()); + if (its_device != "") { + if (setsockopt(acceptor_.native_handle(), SOL_SOCKET, SO_BINDTODEVICE, + its_device.c_str(), static_cast<socklen_t>(its_device.size())) == -1) { + VSOMEIP_WARNING << "TCP Server: Could not bind to device \"" << its_device << "\""; + } + } +#endif + + acceptor_.bind(_local, _error); + if (_error) + return; + + acceptor_.listen(boost::asio::socket_base::max_connections, _error); + if (_error) + return; + + local_ = _local; + local_port_ = _local.port(); + + this->max_message_size_ = configuration_->get_max_message_size_reliable( + _local.address().to_string(), + _local.port()); + this->queue_limit_ = configuration_->get_endpoint_queue_limit(_local.address().to_string(), + _local.port()); +} + +void tcp_server_endpoint_impl::start() { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + connection::ptr new_connection = connection::create( + std::dynamic_pointer_cast<tcp_server_endpoint_impl>( + shared_from_this()), max_message_size_, + buffer_shrink_threshold_, has_enabled_magic_cookies_, + io_, send_timeout_); + + { + std::unique_lock<std::mutex> its_socket_lock(new_connection->get_socket_lock()); + acceptor_.async_accept(new_connection->get_socket(), + std::bind(&tcp_server_endpoint_impl::accept_cbk, + std::dynamic_pointer_cast<tcp_server_endpoint_impl>( + shared_from_this()), new_connection, + std::placeholders::_1)); + } + } +} + +void tcp_server_endpoint_impl::stop() { + server_endpoint_impl::stop(); + { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if(acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } + } + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (const auto &c : connections_) { + c.second->stop(); + } + connections_.clear(); + } +} + +bool tcp_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + std::lock_guard<std::mutex> its_lock(mutex_); + endpoint_type its_target(_target->get_address(), _target->get_port()); + return send_intern(its_target, _data, _size); +} + +bool tcp_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + bool ret(false); + std::lock_guard<std::mutex> its_lock(mutex_); + const endpoint_type its_target(_target->get_address(), _target->get_port()); + const auto its_target_iterator(find_or_create_target_unlocked(its_target)); + auto &its_data = its_target_iterator->second; + + if (check_message_size(nullptr, _size, its_target) == endpoint_impl::cms_ret_e::MSG_OK && + check_queue_limit(_data, _size, its_data)) { + its_data.queue_.emplace_back( + std::make_pair(std::make_shared<message_buffer_t>(_data, _data + _size), 0)); + its_data.queue_size_ += _size; + + if (!its_data.is_sending_) { // no writing in progress + (void)send_queued(its_target_iterator); + } + ret = true; + } + return ret; +} + +bool tcp_server_endpoint_impl::send_queued(const target_data_iterator_type _it) { + + bool must_erase(false); + connection::ptr its_connection; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + auto connection_iterator = connections_.find(_it->first); + if (connection_iterator != connections_.end()) { + its_connection = connection_iterator->second; + if (its_connection) { + its_connection->send_queued(_it); + } + } else { + VSOMEIP_INFO << "Didn't find connection: " + << _it->first.address().to_string() << ":" << std::dec + << static_cast<std::uint16_t>(_it->first.port()) + << " dropping outstanding messages (" << std::dec + << _it->second.queue_.size() << ")."; + + if (_it->second.queue_.size()) { + std::set<service_t> its_services; + + // check all outstanding messages of this connection + // whether stop handlers need to be called + for (const auto &its_q : _it->second.queue_) { + auto its_buffer(its_q.first); + if (its_buffer && its_buffer->size() > VSOMEIP_SESSION_POS_MAX) { + service_t its_service = bithelper::read_uint16_be(&(*its_buffer)[VSOMEIP_SERVICE_POS_MIN]); + its_services.insert(its_service); + } + } + + for (auto its_service : its_services) { + auto found_cbk = prepare_stop_handlers_.find(its_service); + if (found_cbk != prepare_stop_handlers_.end()) { + VSOMEIP_INFO << "Calling prepare stop handler " + << "for service: 0x" + << std::hex << std::setw(4) << std::setfill('0') + << its_service; + auto handler = found_cbk->second; + auto ptr = this->shared_from_this(); + io_.post([ptr, handler]() { handler(ptr); }); + prepare_stop_handlers_.erase(found_cbk); + } + } + } + + // Drop outstanding messages. + _it->second.queue_.clear(); + must_erase = true; + } + } + + return (must_erase); +} + +void tcp_server_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + configuration_->get_configured_timing_responses(_service, + tcp_server_endpoint_base_impl::local_.address().to_string(), + tcp_server_endpoint_base_impl::local_.port(), _method, + _debouncing, _maximum_retention); +} + +bool tcp_server_endpoint_impl::is_established_to(const std::shared_ptr<endpoint_definition>& _endpoint) { + bool is_connected = false; + endpoint_type endpoint(_endpoint->get_address(), _endpoint->get_port()); + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + auto connection_iterator = connections_.find(endpoint); + if (connection_iterator != connections_.end()) { + is_connected = true; + } else { + VSOMEIP_INFO << "Didn't find TCP connection: Subscription " + << "rejected for: " << endpoint.address().to_string() << ":" + << std::dec << static_cast<std::uint16_t>(endpoint.port()); + } + } + return is_connected; +} + +bool tcp_server_endpoint_impl::get_default_target(service_t, + tcp_server_endpoint_impl::endpoint_type &) const { + return false; +} + +void tcp_server_endpoint_impl::remove_connection( + tcp_server_endpoint_impl::connection *_connection) { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (auto it = connections_.begin(); it != connections_.end();) { + if (it->second.get() == _connection) { + it = connections_.erase(it); + break; + } else { + ++it; + } + } +} + +void tcp_server_endpoint_impl::accept_cbk(const connection::ptr& _connection, + boost::system::error_code const &_error) { + + if (!_error) { + boost::system::error_code its_error; + endpoint_type remote; + { + std::unique_lock<std::mutex> its_socket_lock(_connection->get_socket_lock()); + socket_type &new_connection_socket = _connection->get_socket(); + remote = new_connection_socket.remote_endpoint(its_error); + _connection->set_remote_info(remote); + // Nagle algorithm off + new_connection_socket.set_option(ip::tcp::no_delay(true), its_error); + + new_connection_socket.set_option(boost::asio::socket_base::keep_alive(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_server_endpoint::connect: couldn't enable " + << "keep_alive: " << its_error.message(); + } + } + if (!its_error) { + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + connections_[remote] = _connection; + } + _connection->start(); + } + } + if (_error != boost::asio::error::bad_descriptor + && _error != boost::asio::error::operation_aborted + && _error != boost::asio::error::no_descriptors) { + start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR<< "tcp_server_endpoint_impl::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms"; + auto its_timer = + std::make_shared<boost::asio::steady_timer>(io_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<tcp_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error_inner) { + if (!_error_inner) { + its_ep->start(); + } + }); + } +} + +std::uint16_t tcp_server_endpoint_impl::get_local_port() const { + + return local_port_; +} + +void tcp_server_endpoint_impl::set_local_port(std::uint16_t _port) { + (void)_port; +} + +bool tcp_server_endpoint_impl::is_reliable() const { + return true; +} + +bool tcp_server_endpoint_impl::is_suspended() const { + auto its_routing_host { routing_host_.lock() }; + if (its_routing_host) { + return routing_state_e::RS_SUSPENDED == its_routing_host->get_routing_state(); + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// class tcp_service_impl::connection +/////////////////////////////////////////////////////////////////////////////// +tcp_server_endpoint_impl::connection::connection( + const std::weak_ptr<tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _recv_buffer_size_initial, + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_context &_io, + std::chrono::milliseconds _send_timeout) : + socket_(_io), + server_(_server), + max_message_size_(_max_message_size), + recv_buffer_size_initial_(_recv_buffer_size_initial), + recv_buffer_(_recv_buffer_size_initial, 0), + recv_buffer_size_(0), + missing_capacity_(0), + shrink_count_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold), + remote_port_(0), + magic_cookies_enabled_(_magic_cookies_enabled), + last_cookie_sent_(std::chrono::steady_clock::now() - std::chrono::seconds(11)), + send_timeout_(_send_timeout), + send_timeout_warning_(_send_timeout / 2) { +} + +tcp_server_endpoint_impl::connection::~connection() { + + auto its_server(server_.lock()); + if (its_server) { + auto its_routing_host(its_server->routing_host_.lock()); + if (its_routing_host) { + its_routing_host->remove_subscriptions( + its_server->local_port_, + remote_address_, remote_port_); + } + } +} + +tcp_server_endpoint_impl::connection::ptr +tcp_server_endpoint_impl::connection::create( + const std::weak_ptr<tcp_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + bool _magic_cookies_enabled, + boost::asio::io_context &_io, + std::chrono::milliseconds _send_timeout) { + const std::uint32_t its_initial_receveive_buffer_size = + VSOMEIP_SOMEIP_HEADER_SIZE + 8 + MAGIC_COOKIE_SIZE + 8; + return ptr(new connection(_server, _max_message_size, + its_initial_receveive_buffer_size, + _buffer_shrink_threshold, _magic_cookies_enabled, + _io, _send_timeout)); +} + +tcp_server_endpoint_impl::socket_type & +tcp_server_endpoint_impl::connection::get_socket() { + return socket_; +} + +std::unique_lock<std::mutex> +tcp_server_endpoint_impl::connection::get_socket_lock() { + return std::unique_lock<std::mutex>(socket_mutex_); +} + +void tcp_server_endpoint_impl::connection::start() { + receive(); +} + +void tcp_server_endpoint_impl::connection::receive() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if(socket_.is_open()) { + const std::size_t its_capacity(recv_buffer_.capacity()); + if (recv_buffer_size_ > its_capacity) { + VSOMEIP_ERROR << __func__ << "Received buffer size is greater than the buffer capacity!" + << " recv_buffer_size_: " << recv_buffer_size_ + << " its_capacity: " << its_capacity; + return; + } + size_t left_buffer_size = its_capacity - recv_buffer_size_; + try { + if (missing_capacity_) { + if (missing_capacity_ > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!"; + return; + } + const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_); + if (its_capacity < its_required_capacity) { + // Make the resize to its_required_capacity + recv_buffer_.reserve(its_required_capacity); + recv_buffer_.resize(its_required_capacity, 0x0); + if (recv_buffer_.size() > 1048576) { + VSOMEIP_INFO << "tse: recv_buffer size is: " << + recv_buffer_.size() + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + } + left_buffer_size = missing_capacity_; + missing_capacity_ = 0; + } else if (buffer_shrink_threshold_ + && shrink_count_ > buffer_shrink_threshold_ + && recv_buffer_size_ == 0) { + // In this case, make the resize to recv_buffer_size_initial_ + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + // And set buffer_size to recv_buffer_size_initial_, the same of our resize + left_buffer_size = recv_buffer_size_initial_; + shrink_count_ = 0; + } + } catch (const std::exception &e) { + handle_recv_buffer_exception(e); + // don't start receiving again + return; + } + socket_.async_receive(boost::asio::buffer(&recv_buffer_[recv_buffer_size_], left_buffer_size), + std::bind(&tcp_server_endpoint_impl::connection::receive_cbk, + shared_from_this(), std::placeholders::_1, + std::placeholders::_2)); + } +} + +void tcp_server_endpoint_impl::connection::stop() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + boost::system::error_code its_error; + + auto its_server { server_.lock() }; + if (its_server && its_server->is_suspended()) { + socket_.set_option(boost::asio::socket_base::linger(true, 0), its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_server_endpoint_impl::connection::stop< " + << get_address_port_remote() + << ">:setting SO_LINGER failed (" + << its_error.message() + << ")"; + } + } + + socket_.shutdown(socket_.shutdown_both, its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_server_endpoint_impl::connection::stop< " + << get_address_port_remote() + << ">:shutting down socket failed (" + << its_error.message() + << ")"; + } + + socket_.close(its_error); + if (its_error) { + VSOMEIP_WARNING << "tcp_server_endpoint_impl::connection::stop< " + << get_address_port_remote() + << ">:closing socket failed (" + << its_error.message() + << ")"; + } + } +} + +void tcp_server_endpoint_impl::connection::send_queued( + const target_data_iterator_type _it) { + + std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "tcp_server_endpoint_impl::connection::send_queued " + " couldn't lock server_"; + return; + } + message_buffer_ptr_t its_buffer = _it->second.queue_.front().first; + const service_t its_service = bithelper::read_uint16_be(&(*its_buffer)[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&(*its_buffer)[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&(*its_buffer)[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&(*its_buffer)[VSOMEIP_SESSION_POS_MIN]); + if (magic_cookies_enabled_) { + const std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + if (std::chrono::duration_cast<std::chrono::milliseconds>( + now - last_cookie_sent_) > std::chrono::milliseconds(10000)) { + if (send_magic_cookie(its_buffer)) { + last_cookie_sent_ = now; + _it->second.queue_size_ += sizeof(SERVICE_COOKIE); + } + } + } + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + _it->second.is_sending_ = true; + + boost::asio::async_write(socket_, boost::asio::buffer(*its_buffer), + std::bind(&tcp_server_endpoint_impl::connection::write_completion_condition, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + its_buffer->size(), + its_service, its_method, its_client, its_session, + std::chrono::steady_clock::now()), + std::bind(&tcp_server_endpoint_base_impl::send_cbk, + its_server, + _it->first, + std::placeholders::_1, + std::placeholders::_2)); + } +} + +bool tcp_server_endpoint_impl::connection::send_magic_cookie( + message_buffer_ptr_t &_buffer) { + if (max_message_size_ == MESSAGE_SIZE_UNLIMITED + || max_message_size_ - _buffer->size() >= + VSOMEIP_SOMEIP_HEADER_SIZE + VSOMEIP_SOMEIP_MAGIC_COOKIE_SIZE) { + _buffer->insert(_buffer->begin(), SERVICE_COOKIE, + SERVICE_COOKIE + sizeof(SERVICE_COOKIE)); + return true; + } + return false; +} + +bool tcp_server_endpoint_impl::connection::is_magic_cookie(size_t _offset) const { + return (0 == std::memcmp(CLIENT_COOKIE, &recv_buffer_[_offset], + sizeof(CLIENT_COOKIE))); +} + +void tcp_server_endpoint_impl::connection::receive_cbk( + boost::system::error_code const &_error, + std::size_t _bytes) { + if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + return; + } + std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_ERROR << "tcp_server_endpoint_impl::connection::receive_cbk " + " couldn't lock server_"; + return; + } +#if 0 + std::stringstream msg; + for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int) recv_buffer_[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::shared_ptr<routing_host> its_host = its_server->routing_host_.lock(); + if (its_host) { + if (!_error && 0 < _bytes) { + if (recv_buffer_size_ + _bytes < recv_buffer_size_) { + VSOMEIP_ERROR << "receive buffer overflow in tcp client endpoint ~> abort!"; + return; + } + recv_buffer_size_ += _bytes; + + size_t its_iteration_gap = 0; + bool has_full_message; + do { + uint64_t read_message_size + = utility::get_message_size(&recv_buffer_[its_iteration_gap], + recv_buffer_size_); + if (read_message_size > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Message size exceeds allowed maximum!"; + return; + } + uint32_t current_message_size = static_cast<uint32_t>(read_message_size); + has_full_message = (current_message_size > VSOMEIP_RETURN_CODE_POS + && current_message_size <= recv_buffer_size_); + if (has_full_message) { + bool needs_forwarding(true); + if (is_magic_cookie(its_iteration_gap)) { + magic_cookies_enabled_ = true; + } else { + if (magic_cookies_enabled_) { + uint32_t its_offset + = its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], + recv_buffer_size_); + if (its_offset < current_message_size) { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + if (!is_magic_cookie(its_iteration_gap)) { + auto its_endpoint_host = its_server->endpoint_host_.lock(); + if (its_endpoint_host) { + its_endpoint_host->on_error(&recv_buffer_[its_iteration_gap], + static_cast<length_t>(recv_buffer_size_),its_server.get(), + remote_address_, remote_port_); + } + } + current_message_size = its_offset; + needs_forwarding = false; + } + } + } + if (needs_forwarding) { + if (utility::is_request( + recv_buffer_[its_iteration_gap + + VSOMEIP_MESSAGE_TYPE_POS])) { + const client_t its_client = bithelper::read_uint16_be(&recv_buffer_[its_iteration_gap + VSOMEIP_CLIENT_POS_MIN]); + if (its_client != MAGIC_COOKIE_CLIENT) { + const session_t its_session = bithelper::read_uint16_be(&recv_buffer_[its_iteration_gap + VSOMEIP_SESSION_POS_MIN]); + its_server->clients_mutex_.lock(); + its_server->clients_[its_client][its_session] = remote_; + its_server->clients_mutex_.unlock(); + } + } + if (!magic_cookies_enabled_) { + its_host->on_message(&recv_buffer_[its_iteration_gap], + current_message_size, its_server.get(), + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, remote_port_); + } else { + // Only call on_message without a magic cookie in front of the buffer! + if (!is_magic_cookie(its_iteration_gap)) { + its_host->on_message(&recv_buffer_[its_iteration_gap], + current_message_size, its_server.get(), + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, remote_port_); + } + } + } + calculate_shrink_count(); + missing_capacity_ = 0; + recv_buffer_size_ -= current_message_size; + its_iteration_gap += current_message_size; + } else if (magic_cookies_enabled_ && recv_buffer_size_ > 0) { + uint32_t its_offset = + its_server->find_magic_cookie(&recv_buffer_[its_iteration_gap], + recv_buffer_size_); + if (its_offset < recv_buffer_size_) { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Detected Magic Cookie within message data. Resyncing." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + if (!is_magic_cookie(its_iteration_gap)) { + auto its_endpoint_host = its_server->endpoint_host_.lock(); + if (its_endpoint_host) { + its_endpoint_host->on_error(&recv_buffer_[its_iteration_gap], + static_cast<length_t>(recv_buffer_size_), its_server.get(), + remote_address_, remote_port_); + } + } + recv_buffer_size_ -= its_offset; + its_iteration_gap += its_offset; + has_full_message = true; // trigger next loop + if (!is_magic_cookie(its_iteration_gap)) { + auto its_endpoint_host = its_server->endpoint_host_.lock(); + if (its_endpoint_host) { + its_endpoint_host->on_error(&recv_buffer_[its_iteration_gap], + static_cast<length_t>(recv_buffer_size_), its_server.get(), + remote_address_, remote_port_); + } + } + } + } + + if (!has_full_message) { + if (recv_buffer_size_ > VSOMEIP_RETURN_CODE_POS && + (recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION || + !utility::is_valid_message_type(static_cast<message_type_e>(recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS])) || + !utility::is_valid_return_code(static_cast<return_code_e>(recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS])) + )) { + if (recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + // ensure to send back a error message w/ wrong protocol version + its_host->on_message(&recv_buffer_[its_iteration_gap], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, its_server.get(), + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, remote_port_); + } else if (!utility::is_valid_message_type(static_cast<message_type_e>( + recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]))) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]))) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(recv_buffer_[its_iteration_gap + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + wait_until_sent(boost::asio::error::operation_aborted); + return; + } else if (max_message_size_ != MESSAGE_SIZE_UNLIMITED + && current_message_size > max_message_size_) { + recv_buffer_size_ = 0; + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + if (magic_cookies_enabled_) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << " > " << std::dec << max_message_size_ + << "). Magic Cookies are enabled: " + << "Resetting receiver. local: " + << get_address_port_local() << " remote: " + << get_address_port_remote(); + } else { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Received a TCP message which exceeds " + << "maximum message size (" + << std::dec << current_message_size + << " > " << std::dec << max_message_size_ + << ") Magic cookies are disabled: " + << "Connection will be closed! local: " + << get_address_port_local() << " remote: " + << get_address_port_remote(); + } + wait_until_sent(boost::asio::error::operation_aborted); + return; + } + } else if (current_message_size > recv_buffer_size_) { + missing_capacity_ = current_message_size + - static_cast<std::uint32_t>(recv_buffer_size_); + } else if (VSOMEIP_SOMEIP_HEADER_SIZE > recv_buffer_size_) { + missing_capacity_ = VSOMEIP_SOMEIP_HEADER_SIZE + - static_cast<std::uint32_t>(recv_buffer_size_); + } else if (magic_cookies_enabled_ && recv_buffer_size_ > 0) { + // no need to check for magic cookie here again: has_full_message + // would have been set to true if there was one present in the data + recv_buffer_size_ = 0; + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + missing_capacity_ = 0; + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Didn't find magic cookie in broken" + << " data, trying to resync." + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } else { + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "tse::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << recv_buffer_size_ << " but couldn't read " + "out message_size. recv_buffer_capacity: " + << recv_buffer_.capacity() + << " its_iteration_gap: " << its_iteration_gap + << "local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << ". Closing connection due to missing/broken data TCP stream."; + } + wait_until_sent(boost::asio::error::operation_aborted); + return; + } + } + } while (has_full_message && recv_buffer_size_); + if (its_iteration_gap) { + // Copy incomplete message to front for next receive_cbk iteration + for (size_t i = 0; i < recv_buffer_size_; ++i) { + recv_buffer_[i] = recv_buffer_[i + its_iteration_gap]; + } + // Still more capacity needed after shifting everything to front? + if (missing_capacity_ && + missing_capacity_ <= recv_buffer_.capacity() - recv_buffer_size_) { + missing_capacity_ = 0; + } + } + receive(); + } + } + if (_error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset + || _error == boost::asio::error::timed_out) { + if(_error == boost::asio::error::timed_out) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_WARNING << "tcp_server_endpoint receive_cbk: " << _error.message() + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + wait_until_sent(boost::asio::error::operation_aborted); + } +} + +void tcp_server_endpoint_impl::connection::calculate_shrink_count() { + if (buffer_shrink_threshold_) { + if (recv_buffer_.capacity() != recv_buffer_size_initial_) { + if (recv_buffer_size_ < (recv_buffer_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + } +} + +void tcp_server_endpoint_impl::connection::set_remote_info( + const endpoint_type &_remote) { + remote_ = _remote; + remote_address_ = _remote.address(); + remote_port_ = _remote.port(); +} + +std::string tcp_server_endpoint_impl::connection::get_address_port_remote() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + its_address_port += remote_address_.to_string(ec); + its_address_port += ":"; + its_address_port += std::to_string(remote_port_); + return its_address_port; +} + +std::string tcp_server_endpoint_impl::connection::get_address_port_local() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + if (socket_.is_open()) { + endpoint_type its_local_endpoint = socket_.local_endpoint(ec); + if (!ec) { + its_address_port += its_local_endpoint.address().to_string(ec); + its_address_port += ":"; + its_address_port += std::to_string(its_local_endpoint.port()); + } + } + return its_address_port; +} + +void tcp_server_endpoint_impl::connection::handle_recv_buffer_exception( + const std::exception &_e) { + std::stringstream its_message; + its_message << "tcp_server_endpoint_impl::connection catched exception" + << _e.what() << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << " shutting down connection. Start of buffer: " + << std::setfill('0') << std::hex; + + for (std::size_t i = 0; i < recv_buffer_size_ && i < 16; i++) { + its_message << std::setw(2) << static_cast<int>(recv_buffer_[i]) << " "; + } + + its_message << " Last 16 Bytes captured: "; + for (int i = 15; recv_buffer_size_ > 15 && i >= 0; i--) { + its_message << std::setw(2) << static_cast<int>(recv_buffer_[static_cast<size_t>(i)]) << " "; + } + VSOMEIP_ERROR << its_message.str(); + recv_buffer_.clear(); + if (socket_.is_open()) { + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + } + std::shared_ptr<tcp_server_endpoint_impl> its_server = server_.lock(); + if (its_server) { + its_server->remove_connection(this); + } +} + +std::size_t +tcp_server_endpoint_impl::connection::get_recv_buffer_capacity() const { + return recv_buffer_.capacity(); +} + +std::size_t +tcp_server_endpoint_impl::connection::write_completion_condition( + const boost::system::error_code& _error, + std::size_t _bytes_transferred, std::size_t _bytes_to_send, + service_t _service, method_t _method, client_t _client, session_t _session, + const std::chrono::steady_clock::time_point _start) { + if (_error) { + VSOMEIP_ERROR << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send << " " + << "remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + stop_and_remove_connection(); + return 0; + } + + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::milliseconds passed = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start); + if (passed > send_timeout_warning_) { + if (passed > send_timeout_) { + VSOMEIP_ERROR << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send + << " remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + } else { + VSOMEIP_WARNING << "tse::write_completion_condition: " + << _error.message() << "(" << std::dec << _error.value() + << ") took longer than " << std::dec << send_timeout_warning_.count() + << "ms bytes transferred: " << std::dec << _bytes_transferred + << " bytes to sent: " << std::dec << _bytes_to_send + << " remote:" << get_address_port_remote() << " (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _method << "." + << std::setw(4) << _session << "]"; + } + } + return _bytes_to_send - _bytes_transferred; +} + +void tcp_server_endpoint_impl::connection::stop_and_remove_connection() { + std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_ERROR << "tse::connection::stop_and_remove_connection " + " couldn't lock server_"; + return; + } + { + std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); +} + +// Dummies +void tcp_server_endpoint_impl::receive() { + // intentionally left empty +} + +void tcp_server_endpoint_impl::print_status() { + std::lock_guard<std::mutex> its_lock(mutex_); + connections_t its_connections; + { + std::lock_guard<std::mutex> its_lock_inner(connections_mutex_); + its_connections = connections_; + } + + VSOMEIP_INFO << "status tse: " << std::dec << local_port_ + << " connections: " << std::dec << its_connections.size() + << " targets: " << std::dec << targets_.size(); + for (const auto &c : its_connections) { + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + std::size_t its_recv_size(0); + { + std::unique_lock<std::mutex> c_s_lock(c.second->get_socket_lock()); + its_recv_size = c.second->get_recv_buffer_capacity(); + } + auto found_queue = targets_.find(c.first); + if (found_queue != targets_.end()) { + its_queue_size = found_queue->second.queue_.size(); + its_data_size = found_queue->second.queue_size_; + } + VSOMEIP_INFO << "status tse: client: " + << c.second->get_address_port_remote() + << " queue: " << std::dec << its_queue_size + << " data: " << std::dec << its_data_size + << " recv_buffer: " << std::dec << its_recv_size; + } +} + +std::string tcp_server_endpoint_impl::get_remote_information( + const target_data_iterator_type _it) const { + boost::system::error_code ec; + return _it->first.address().to_string(ec) + ":" + + std::to_string(_it->first.port()); +} + +std::string tcp_server_endpoint_impl::get_remote_information( + const endpoint_type& _remote) const { + boost::system::error_code ec; + return _remote.address().to_string(ec) + ":" + + std::to_string(_remote.port()); +} + +void tcp_server_endpoint_impl::connection::wait_until_sent(const boost::system::error_code &_error) { + + std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) + return; + + std::lock_guard<std::mutex> its_lock(its_server->mutex_); + auto it = its_server->targets_.find(remote_); + if (it != its_server->targets_.end()) { + auto &its_data = it->second; + if (its_data.is_sending_ && _error) { + std::chrono::milliseconds its_timeout(VSOMEIP_MAX_TCP_SENT_WAIT_TIME); + boost::system::error_code ec; + its_data.sent_timer_.expires_from_now(its_timeout, ec); + its_data.sent_timer_.async_wait(std::bind(&tcp_server_endpoint_impl::connection::wait_until_sent, + std::dynamic_pointer_cast<tcp_server_endpoint_impl::connection>(shared_from_this()), + std::placeholders::_1)); + return; + } else { + VSOMEIP_WARNING << __func__ + << ": Maximum wait time for send operation exceeded for tse."; + } + } + { + std::lock_guard<std::mutex> its_lock_inner(its_server->connections_mutex_); + stop(); + } + its_server->remove_connection(this); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp.cpp new file mode 100644 index 00000000000..b0879aafd1b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2019-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/tp.hpp" + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <arpa/inet.h> +#else +#include <Winsock2.h> +#endif + + +namespace vsomeip_v3 { +namespace tp { + +tp_split_messages_t +tp::tp_split_message(const std::uint8_t * const _data, std::uint32_t _size, + std::uint16_t _max_segment_length) { + + tp_split_messages_t split_messages; + + if (_size < VSOMEIP_MAX_UDP_MESSAGE_SIZE) { + VSOMEIP_ERROR << __func__ << " called with size: " << std::dec << _size; + return split_messages; + } + + const auto data_end = _data + _size; + for (auto current_offset = _data + VSOMEIP_FULL_HEADER_SIZE; current_offset < data_end;) { + auto msg = std::make_shared<message_buffer_t>(); + msg->reserve(VSOMEIP_FULL_HEADER_SIZE + sizeof(tp_header_t) + _max_segment_length); + // copy the header + msg->insert(msg->end(), _data, _data + VSOMEIP_FULL_HEADER_SIZE); + // change the message type + (*msg)[VSOMEIP_MESSAGE_TYPE_POS] = (*msg)[VSOMEIP_MESSAGE_TYPE_POS] | 0x20; + // check if last segment + const auto segment_end = current_offset + _max_segment_length; + const bool is_last_segment = (segment_end >= data_end); + // insert tp_header + const tp_header_t header = htonl( + static_cast<tp_header_t>((current_offset - VSOMEIP_FULL_HEADER_SIZE - _data)) | + static_cast<tp_header_t>(is_last_segment ? 0x0u : 0x1u)); + + const byte_t * const headerp = reinterpret_cast<const byte_t*>(&header); + msg->insert(msg->end(), headerp, headerp + sizeof(tp_header_t)); + + // insert payload + if (is_last_segment) { + msg->insert(msg->end(), current_offset, data_end); + current_offset = data_end; + } else { + msg->insert(msg->end(), current_offset, segment_end); + current_offset += _max_segment_length; + } + // update length + const length_t its_length = static_cast<length_t>(msg->size() + - VSOMEIP_SOMEIP_HEADER_SIZE); + *(reinterpret_cast<length_t*>(&(*msg)[VSOMEIP_LENGTH_POS_MIN])) = htonl(its_length); + split_messages.emplace_back(std::move(msg)); + } + + return split_messages; +} + +const std::uint16_t tp::tp_max_segment_length_; + +} // namespace tp +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_message.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_message.cpp new file mode 100644 index 00000000000..7cb77b804a7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_message.cpp @@ -0,0 +1,347 @@ +// Copyright (C) 2019-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <sstream> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/tp_message.hpp" +#include "../include/tp.hpp" +#include "../../utility/include/bithelper.hpp" + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <arpa/inet.h> +#else +#include <Winsock2.h> +#endif + + +namespace vsomeip_v3 { +namespace tp { + +tp_message::tp_message(const byte_t* const _data, std::uint32_t _data_length, + std::uint32_t _max_message_size) : + timepoint_creation_(std::chrono::steady_clock::now()), + max_message_size_(_max_message_size), + current_message_size_(0), + last_segment_received_(false) { + if (_data_length < VSOMEIP_FULL_HEADER_SIZE + VSOMEIP_TP_HEADER_SIZE) { + VSOMEIP_ERROR << __func__ << " received too short SOME/IP-TP message " + << get_message_id(_data, _data_length); + return; + } + // copy header + message_.insert(message_.end(), _data, _data + VSOMEIP_FULL_HEADER_SIZE); + // remove TP flag + message_[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<byte_t>(tp::tp_flag_unset( + message_[VSOMEIP_MESSAGE_TYPE_POS])); + + const length_t its_segment_size = _data_length - VSOMEIP_FULL_HEADER_SIZE + - VSOMEIP_TP_HEADER_SIZE; + const tp_header_t its_tp_header = bithelper::read_uint32_be(&_data[VSOMEIP_TP_HEADER_POS_MIN]); + + if (check_lengths(_data, _data_length, its_segment_size, + tp::more_segments(its_tp_header))) { + const length_t its_offset = tp::get_offset(its_tp_header); + segments_.emplace(segment_t(its_offset, its_offset + its_segment_size - 1)); + if (its_offset != 0) { + // segment different than the first segment was received + message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0); + if (!tp::more_segments(its_tp_header)) { + // received the last segment of the segmented message first + last_segment_received_ = true; + } + } + message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS], + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size); + current_message_size_ += VSOMEIP_FULL_HEADER_SIZE + its_segment_size; + } +} + +bool tp_message::add_segment(const byte_t* const _data, + std::uint32_t _data_length) { + if (_data_length < VSOMEIP_FULL_HEADER_SIZE + VSOMEIP_TP_HEADER_SIZE) { + VSOMEIP_ERROR << __func__ << " received too short SOME/IP-TP message " + << get_message_id(_data, _data_length); + return false; + } + bool ret = false; + + const length_t its_segment_size = _data_length - VSOMEIP_FULL_HEADER_SIZE + - VSOMEIP_TP_HEADER_SIZE; + const tp_header_t its_tp_header = bithelper::read_uint32_be(&_data[VSOMEIP_TP_HEADER_POS_MIN]); + + if (check_lengths(_data, _data_length, its_segment_size, + tp::more_segments(its_tp_header))) { + const length_t its_offset = tp::get_offset(its_tp_header); + const auto emplace_res = segments_.emplace( + segment_t(its_offset, its_offset + its_segment_size - 1)); + if (!emplace_res.second) { + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " received duplicate segment " << get_message_id(_data, _data_length) + << "TP offset: 0x" << std::hex << its_offset; + } else { + const auto& seg_current = emplace_res.first; + const auto& seg_next = std::next(seg_current); + const bool current_segment_is_last = (seg_next == segments_.end()); + const bool current_segment_is_first = (seg_current == segments_.begin()); + if (current_segment_is_last) { + if (current_segment_is_first) { + // received segment of message but the first received segment was invalid + // resize + append + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " received 2nd segment of message. But the " + "first received segment already wasn't accepted. " + "The message can't be completed anymore: " + << get_message_id(_data, _data_length); + if (its_offset != 0) { + // segment different than the first segment was received + message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0); + if (!tp::more_segments(its_tp_header)) { + // received the last segment of the segmented message first + last_segment_received_ = true; + } + } + // append to end of message + message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS], + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size); + current_message_size_ += its_segment_size; + } else { + const auto& seg_prev = std::prev(seg_current); + if (seg_prev->end_ < seg_current->start_) { + const bool direct_previous_segment_present = (seg_prev->end_ + 1 == seg_current->start_); + if (!direct_previous_segment_present) { + // received segment out of order behind the current end of received segments + //resize + append + message_.resize(VSOMEIP_FULL_HEADER_SIZE + its_offset, 0x0); + } + // append to end of message + message_.insert(message_.end(), &_data[VSOMEIP_TP_PAYLOAD_POS], + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size); + current_message_size_ += its_segment_size; + } else { + // this segment starts before the end of the previous and + // would overwrite already received data + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " completely accepting segment would overwrite previous segment " + << get_message_id(_data, _data_length) + << "previous segment end: " << std::dec << seg_prev->end_ + 1 + << " this segment start: " << std::dec << seg_current->start_; + message_.insert(message_.end(), + &_data[VSOMEIP_TP_PAYLOAD_POS] + ((seg_prev->end_ + 1) - seg_current->start_), + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_segment_size); + // update start of current segment + const std::uint32_t current_end = seg_current->end_; + segments_.erase(seg_current); + segments_.emplace(segment_t(seg_prev->end_ + 1, current_end)); + current_message_size_ += current_end - seg_prev->end_; + } + } + } else { + // received segment in wrong order and other segments afterwards were already received + if ((seg_current != segments_.begin() && std::prev(seg_current)->end_ < seg_current->start_) + || seg_current == segments_.begin()) { // no need to check prev_segment if current segment is the first + if (seg_current->end_ < seg_next->start_) { + std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_offset], &_data[VSOMEIP_TP_PAYLOAD_POS], its_segment_size); + current_message_size_ += its_segment_size; + } else { + // this segment ends after the start of the next and + // would overwrite already received data + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " completely accepting segment would overwrite next segment " + << get_message_id(_data, _data_length) + << "next segment start: " << std::dec << seg_next->start_ + << " this segment end: " << std::dec << seg_current->end_ + 1; + std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_offset], &_data[VSOMEIP_TP_PAYLOAD_POS], seg_next->start_ - its_offset); + // update current segment length to match size of memory + std::uint32_t current_start = seg_current->start_; + segments_.erase(seg_current); + segments_.emplace(segment_t(current_start, seg_next->start_ - 1)); + current_message_size_ += seg_next->start_ - current_start; + } + } else if (seg_current->end_ < seg_next->start_) { + // this segment starts before the end of the previous and + // would overwrite already received data. But ends before the + // start of the next segment + const auto& seg_prev = std::prev(seg_current); + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " completely accepting segment would overwrite previous segment " + << get_message_id(_data, _data_length) + << "previous segment end: " << std::dec << seg_prev->end_ + << " this segment start: " << std::dec << seg_current->start_; + const length_t its_corrected_offset = seg_prev->end_ + 1; + std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_corrected_offset], + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_corrected_offset - its_offset, + seg_next->start_ - its_corrected_offset); + // update current segment length to match size of memory + std::uint32_t current_end = seg_current->end_; + segments_.erase(seg_current); + segments_.emplace(segment_t(seg_prev->end_ + 1, current_end)); + current_message_size_ += current_end - seg_prev->end_; + } else { + // this segment starts before the end of the previous and + // ends after the start of the next segment and would + // overwrite already received data. + const auto& seg_prev = std::prev(seg_current); + VSOMEIP_WARNING << __func__ << ":" << __LINE__ + << " completely accepting segment would overwrite " + << "previous and next segment " + << get_message_id(_data, _data_length) + << "previous segment end: " << std::dec << seg_prev->end_ + << " this segment start: " << std::dec << seg_current->start_ + << " this segment end: " << std::dec << seg_current->end_ + << " next segment start: " << std::dec << seg_next->start_; + const length_t its_corrected_offset = seg_prev->end_ + 1; + std::memcpy(&message_[VSOMEIP_FULL_HEADER_SIZE + its_corrected_offset], + &_data[VSOMEIP_TP_PAYLOAD_POS] + its_corrected_offset - its_offset, + seg_next->start_ - its_corrected_offset); + segments_.erase(seg_current); + segments_.emplace(segment_t(seg_prev->end_ + 1, seg_next->start_ - 1)); + current_message_size_ += seg_next->start_ - (seg_prev->end_ + 1); + } + } + if (!tp::more_segments(its_tp_header)) { + // received the last segment + last_segment_received_ = true; + } + if (last_segment_received_) { + // check if all segments are present + std::uint32_t last_end = std::numeric_limits<std::uint32_t>::max(); + bool complete(true); + for (const auto& seg : segments_) { + if (last_end + 1 != seg.start_) { + complete = false; + break; + } else { + last_end = seg.end_; + } + } + if (complete) { + // all segments were received -> update length field of message + const length_t its_length = static_cast<length_t>( + message_.size() - VSOMEIP_SOMEIP_HEADER_SIZE); + *(reinterpret_cast<length_t*>(&message_[VSOMEIP_LENGTH_POS_MIN])) = htonl(its_length); + // all segments were received -> update return code field of message + message_[VSOMEIP_RETURN_CODE_POS] = _data[VSOMEIP_RETURN_CODE_POS]; + ret = true; + } + } + } + } + return ret; +} + +message_buffer_t tp_message::get_message() { + return std::move(message_); +} + +std::chrono::steady_clock::time_point tp_message::get_creation_time() const { + return timepoint_creation_; +} + +std::string tp_message::get_message_id(const byte_t* const _data, std::uint32_t _data_length) { + std::stringstream ss; + if (_data_length >= VSOMEIP_FULL_HEADER_SIZE) { + + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const service_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + const service_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + const service_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + const interface_version_t its_interface_version = + _data[VSOMEIP_INTERFACE_VERSION_POS]; + const message_type_e its_msg_type = tp::tp_flag_unset( + _data[VSOMEIP_MESSAGE_TYPE_POS]); + + ss << "(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << ") [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(2) << std::uint32_t(its_interface_version) << "." + << std::setw(2) << std::uint32_t(its_msg_type) << "." + << std::setw(4) << its_session + << "] "; + if (_data_length > VSOMEIP_TP_HEADER_POS_MAX) { + const tp_header_t its_tp_header = bithelper::read_uint32_be(&_data[VSOMEIP_TP_HEADER_POS_MIN]); + const length_t its_offset = tp::get_offset(its_tp_header); + ss << " TP offset: 0x" << std::hex << its_offset << " "; + } + } + return ss.str(); +} + +bool tp_message::check_lengths(const byte_t* const _data, + std::uint32_t _data_length, + length_t _segment_size, bool _more_fragments) { + + const length_t its_length = bithelper::read_uint32_be(&_data[VSOMEIP_LENGTH_POS_MIN]); + const tp_header_t its_tp_header = bithelper::read_uint32_be(&_data[VSOMEIP_TP_HEADER_POS_MIN]); + bool ret(true); + + if (!tp::tp_flag_is_set(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + VSOMEIP_ERROR << __func__ << ": TP flag not set " + << get_message_id(_data, _data_length); + ret = false; + } else if (_data_length != its_length + VSOMEIP_SOMEIP_HEADER_SIZE) { + VSOMEIP_ERROR << __func__ + << ": data length doesn't match header length field" + << get_message_id(_data, _data_length) + << " data: " << std::dec << _data_length + << " header: " << std::dec << its_length; + ret = false; + } else if (_segment_size != its_length - VSOMEIP_TP_HEADER_SIZE + - (VSOMEIP_FULL_HEADER_SIZE - VSOMEIP_SOMEIP_HEADER_SIZE)) { + VSOMEIP_ERROR << __func__ + << ": segment size doesn't align with header length field" + << get_message_id(_data, _data_length) + << "segment size: " << std::dec << _segment_size + << " data: " << std::dec << _data_length + << " header: " << std::dec << its_length; + ret = false; + } else if (_segment_size > tp::tp_max_segment_length_) { + VSOMEIP_ERROR << __func__ << ": Segment exceeds allowed size " + << get_message_id(_data, _data_length) + << "segment size: " << std::dec << _segment_size << " (max. " + << std::dec << tp::tp_max_segment_length_ + << ") data: " << std::dec << _data_length + << " header: " << std::dec << its_length; + ret = false; + } else if (_more_fragments && _segment_size % 16 > 0) { + VSOMEIP_ERROR << __func__ << ": Segment size not multiple of 16 " + << get_message_id(_data, _data_length) + << "segment size: " << std::dec << _segment_size + << " data: " << std::dec << _data_length + << " header: " << std::dec << its_length; + ret = false; + } else if (current_message_size_ + _segment_size > max_message_size_ + || current_message_size_ + _segment_size < _segment_size) { // overflow check + VSOMEIP_ERROR << __func__ << ": Message exceeds maximum configured size: " + << get_message_id(_data, _data_length) + << "segment size: " << std::dec << _segment_size + << " current message size: " << std::dec << current_message_size_ + << " maximum message size: " << std::dec << max_message_size_; + ret = false; + } else if (tp::get_offset(its_tp_header) + _segment_size > max_message_size_ + || tp::get_offset(its_tp_header) + _segment_size < _segment_size) { // overflow check + VSOMEIP_ERROR << __func__ << ": SomeIP/TP offset field exceeds maximum configured message size: " + << get_message_id(_data, _data_length) + << " TP offset [bytes]: " << std::dec << tp::get_offset(its_tp_header) + << " segment size: " << std::dec << _segment_size + << " current message size: " << std::dec << current_message_size_ + << " maximum message size: " << std::dec << max_message_size_; + ret = false; + } + return ret; +} + +} // namespace tp +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_reassembler.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_reassembler.cpp new file mode 100644 index 00000000000..f235957fcd6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/tp_reassembler.cpp @@ -0,0 +1,199 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "../include/tp_reassembler.hpp" + +#include <vsomeip/defines.hpp> +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/tp.hpp" +#include "../../utility/include/bithelper.hpp" + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +namespace vsomeip_v3 { +namespace tp { + +tp_reassembler::tp_reassembler(std::uint32_t _max_message_size, boost::asio::io_context &_io) : + max_message_size_(_max_message_size), + cleanup_timer_running_(false), + cleanup_timer_(_io) { +} + +std::pair<bool, message_buffer_t> tp_reassembler::process_tp_message( + const byte_t* const _data, std::uint32_t _data_size, + const boost::asio::ip::address& _address, std::uint16_t _port) { + std::pair<bool, message_buffer_t> ret; + if (_data_size < VSOMEIP_FULL_HEADER_SIZE) { + return std::make_pair(false, message_buffer_t()); + } + + cleanup_timer_start(false); + + const service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + const method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + const interface_version_t its_interface_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; + const message_type_e its_msg_type = tp::tp_flag_unset(_data[VSOMEIP_MESSAGE_TYPE_POS]); + + const std::uint64_t its_tp_message_id = ((static_cast<std::uint64_t>(its_service) << 48) | + (static_cast<std::uint64_t>(its_method) << 32) | + (static_cast<std::uint64_t>(its_client) << 16) | + (static_cast<std::uint64_t>(its_interface_version) << 8) | + (static_cast<std::uint64_t>(its_msg_type))); + + std::lock_guard<std::mutex> its_lock(mutex_); + ret.first = false; + const auto found_ip = tp_messages_.find(_address); + if (found_ip != tp_messages_.end()) { + const auto found_port = found_ip->second.find(_port); + if (found_port != found_ip->second.end()) { + auto found_tp_msg = found_port->second.find(its_tp_message_id); + if (found_tp_msg != found_port->second.end()) { + if (found_tp_msg->second.first == its_session) { + // received additional segment for already known message + if (found_tp_msg->second.second.add_segment(_data, _data_size)) { + // message is complete + ret.first = true; + ret.second = found_tp_msg->second.second.get_message(); + // cleanup tp_message as message was moved and cleanup map + found_port->second.erase(its_tp_message_id); + if (found_port->second.empty()) { + found_ip->second.erase(found_port); + if (found_ip->second.empty()) { + tp_messages_.erase(found_ip); + } + } + } + } else { + VSOMEIP_WARNING << __func__ << ": Received new segment " + "although old one is not finished yet. Dropping " + "old. (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << ") [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(2) << std::uint32_t(its_interface_version) << "." + << std::setw(2) << std::uint32_t(its_msg_type) << "] Old: 0x" + << std::setw(4) << found_tp_msg->second.first << ", new: 0x" + << std::setw(4) << its_session; + // new segment with different session id -> throw away current + found_tp_msg->second.first = its_session; + found_tp_msg->second.second = tp_message(_data, _data_size, max_message_size_); + } + } else { + found_port->second.emplace( + std::make_pair(its_tp_message_id, + std::make_pair(its_session, + tp_message(_data, _data_size, max_message_size_)))); + } + } else { + found_ip->second[_port].emplace( + std::make_pair(its_tp_message_id, + std::make_pair(its_session, + tp_message(_data, _data_size, max_message_size_)))); + } + } else { + tp_messages_[_address][_port].emplace( + std::make_pair(its_tp_message_id, + std::make_pair(its_session, + tp_message(_data, _data_size, max_message_size_)))); + } + return ret; +} + +bool tp_reassembler::cleanup_unfinished_messages() { + std::lock_guard<std::mutex> its_lock(mutex_); + const std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + for (auto ip_iter = tp_messages_.begin(); ip_iter != tp_messages_.end();) { + for (auto port_iter = ip_iter->second.begin(); + port_iter != ip_iter->second.end();) { + for (auto tp_id_iter = port_iter->second.begin(); + tp_id_iter != port_iter->second.end();) { + if (std::chrono::duration_cast<std::chrono::milliseconds>( + now - tp_id_iter->second.second.get_creation_time()).count() + > 5000) { + // message is older than 5 seconds delete it + const auto its_service = static_cast<service_t>(tp_id_iter->first >> 48); + const auto its_method = static_cast<method_t>(tp_id_iter->first >> 32); + const auto its_client = static_cast<client_t>(tp_id_iter->first >> 16); + const auto its_interface_version = static_cast<interface_version_t>(tp_id_iter->first >> 8); + const auto its_msg_type = static_cast<message_type_e>(tp_id_iter->first >> 0); + VSOMEIP_WARNING << __func__ + << ": deleting unfinished SOME/IP-TP message from: " + << ip_iter->first.to_string() << ":" << std::dec + << port_iter->first << " (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << ") [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(2) << std::uint32_t(its_interface_version) << "." + << std::setw(2) << std::uint32_t(its_msg_type) << "." + << std::setw(4) << tp_id_iter->second.first << "]"; + tp_id_iter = port_iter->second.erase(tp_id_iter); + } else { + tp_id_iter++; + } + } + if (port_iter->second.empty()) { + port_iter = ip_iter->second.erase(port_iter); + } else { + port_iter++; + } + } + if (ip_iter->second.empty()) { + ip_iter = tp_messages_.erase(ip_iter); + } else { + ip_iter++; + } + } + return !tp_messages_.empty(); +} + +void tp_reassembler::stop() { + std::lock_guard<std::mutex> its_lock(cleanup_timer_mutex_); + boost::system::error_code ec; + cleanup_timer_.cancel(ec); +} + +void tp_reassembler::cleanup_timer_start(bool _force) { + std::lock_guard<std::mutex> its_lock(cleanup_timer_mutex_); + cleanup_timer_start_unlocked(_force); +} + +void tp_reassembler::cleanup_timer_start_unlocked(bool _force) { + if (!cleanup_timer_running_ || _force) { + cleanup_timer_.expires_from_now(std::chrono::seconds(5)); + cleanup_timer_running_ = true; + cleanup_timer_.async_wait( + std::bind(&tp_reassembler::cleanup_timer_cbk, + shared_from_this(), std::placeholders::_1)); + } +} + +void tp_reassembler::cleanup_timer_cbk( + const boost::system::error_code _error) { + if (!_error) { + std::lock_guard<std::mutex> its_lock(cleanup_timer_mutex_); + if (cleanup_unfinished_messages()) { + cleanup_timer_start_unlocked(true); + } else { + // don't start timer again as there are no more segmented messages present + cleanup_timer_running_ = false; + } + } +} + +} //namespace tp +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_client_endpoint_impl.cpp new file mode 100644 index 00000000000..4f7bd46acf6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_client_endpoint_impl.cpp @@ -0,0 +1,671 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <sstream> +#include <thread> + +#include <boost/asio/ip/multicast.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_host.hpp" +#include "../include/tp.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../include/udp_client_endpoint_impl.hpp" +#include "../../utility/include/utility.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +udp_client_endpoint_impl::udp_client_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, + const endpoint_type& _remote, + boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration) + : udp_client_endpoint_base_impl(_endpoint_host, _routing_host, _local, _remote, _io, + _configuration), + remote_address_(_remote.address()), + remote_port_(_remote.port()), + udp_receive_buffer_size_(_configuration->get_udp_receive_buffer_size()), + tp_reassembler_(std::make_shared<tp::tp_reassembler>( + _configuration->get_max_message_size_unreliable(), _io)) { + is_supporting_someip_tp_ = true; + + this->max_message_size_ = VSOMEIP_MAX_UDP_MESSAGE_SIZE; + this->queue_limit_ = _configuration->get_endpoint_queue_limit(_remote.address().to_string(), + _remote.port()); +} + +udp_client_endpoint_impl::~udp_client_endpoint_impl() { + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + its_host->release_port(local_.port(), false); + } + tp_reassembler_->stop(); +} + +bool udp_client_endpoint_impl::is_local() const { + return false; +} + +void udp_client_endpoint_impl::connect() { + std::unique_lock<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + socket_->open(remote_.protocol(), its_error); + if (!its_error || its_error == boost::asio::error::already_open) { + // Enable SO_REUSEADDR to avoid bind problems with services going offline + // and coming online again and the user has specified only a small number + // of ports in the clients section for one service instance + socket_->set_option(boost::asio::socket_base::reuse_address(true), its_error); + if (its_error) { + VSOMEIP_WARNING << "udp_client_endpoint_impl::connect: couldn't enable " + << "SO_REUSEADDR: " << its_error.message() << " remote:" + << get_address_port_remote(); + } + socket_->set_option(boost::asio::socket_base::receive_buffer_size( + static_cast<int>(udp_receive_buffer_size_)), its_error); + if (its_error) { + VSOMEIP_WARNING << "udp_client_endpoint_impl::connect: couldn't set " + << "SO_RCVBUF: " << its_error.message() + << " to: " << std::dec << udp_receive_buffer_size_ + << " local port:" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } + + boost::asio::socket_base::receive_buffer_size its_option; + socket_->get_option(its_option, its_error); + #ifdef __linux__ + // If regular setting of the buffer size did not work, try to force + // (requires CAP_NET_ADMIN to be successful) + if (its_option.value() < 0 + || its_option.value() < udp_receive_buffer_size_) { + its_error.assign(setsockopt(socket_->native_handle(), + SOL_SOCKET, SO_RCVBUFFORCE, + &udp_receive_buffer_size_, sizeof(udp_receive_buffer_size_)), + boost::system::generic_category()); + if (!its_error) { + VSOMEIP_INFO << "udp_client_endpoint_impl::connect: " + << "SO_RCVBUFFORCE successful!"; + } + socket_->get_option(its_option, its_error); + } + #endif + if (its_error) { + VSOMEIP_WARNING << "udp_client_endpoint_impl::connect: couldn't get " + << "SO_RCVBUF: " << its_error.message() + << " local port:" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } else { + VSOMEIP_INFO << "udp_client_endpoint_impl::connect: SO_RCVBUF is: " + << std::dec << its_option.value() + << " (" << udp_receive_buffer_size_ << ")" + << " local port:" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } + + if (local_.port() == ILLEGAL_PORT) { + // Let the OS assign the port + local_.port(0); + } + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // If specified, bind to device + std::string its_device(configuration_->get_device()); + if (its_device != "") { + if (setsockopt(socket_->native_handle(), + SOL_SOCKET, SO_BINDTODEVICE, its_device.c_str(), socklen_t(its_device.size())) == -1) { + VSOMEIP_WARNING << "UDP Client: Could not bind to device \"" << its_device << "\""; + } + } +#endif + + // In case a client endpoint port was configured, + // bind to it before connecting + if (local_.port() != ILLEGAL_PORT) { + boost::system::error_code its_bind_error; + socket_->bind(local_, its_bind_error); + if(its_bind_error) { + VSOMEIP_WARNING << "udp_client_endpoint::connect: " + "Error binding socket: " << its_bind_error.message() + << " local: " << local_.address().to_string() + << ":" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + + its_lock.unlock(); + + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + // set new client port depending on service / instance / remote port + if (!its_host->on_bind_error(shared_from_this(), remote_address_, remote_port_)) { + VSOMEIP_WARNING << "udp_client_endpoint::connect: " + "Failed to set new local port for uce: " + << " local: " << local_.address().to_string() + << ":" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } else { + VSOMEIP_INFO << "udp_client_endpoint::connect: " + "Using new new local port for uce: " + << " local: " << local_.address().to_string() + << ":" << std::dec << local_.port() + << " remote:" << get_address_port_remote(); + } + } + + + try { + // don't connect on bind error to avoid using a random port + strand_.post(std::bind(&client_endpoint_impl::connect_cbk, + shared_from_this(), its_bind_error)); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "udp_client_endpoint_impl::connect: " + << e.what() << " remote:" << get_address_port_remote(); + } + return; + } + } + + state_ = cei_state_e::CONNECTING; + socket_->async_connect( + remote_, + strand_.wrap( + std::bind( + &udp_client_endpoint_base_impl::connect_cbk, + shared_from_this(), + std::placeholders::_1 + ) + ) + ); + } else { + VSOMEIP_WARNING << "udp_client_endpoint::connect: Error opening socket: " + << its_error.message() << " remote:" << get_address_port_remote(); + strand_.post(std::bind(&udp_client_endpoint_base_impl::connect_cbk, + shared_from_this(), its_error)); + } +} + +void udp_client_endpoint_impl::start() { + connect(); +} + +void udp_client_endpoint_impl::restart(bool _force) { + if (!_force && state_ == cei_state_e::CONNECTING) { + return; + } + state_ = cei_state_e::CONNECTING; + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + queue_.clear(); + } + std::string local; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + local = get_address_port_local(); + } + shutdown_and_close_socket(false); + was_not_connected_ = true; + reconnect_counter_ = 0; + VSOMEIP_WARNING << "uce::restart: local: " << local + << " remote: " << get_address_port_remote(); + start_connect_timer(); +} + +void udp_client_endpoint_impl::send_queued(std::pair<message_buffer_ptr_t, uint32_t> &_entry) { + +#if 0 + std::stringstream msg; + msg << "ucei<" << remote_.address() << ":" + << std::dec << remote_.port() << ">::sq: "; + for (std::size_t i = 0; i < _buffer->size(); i++) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int)(*_entry.first)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + { + std::lock_guard<std::mutex> its_last_sent_lock(last_sent_mutex_); + std::lock_guard<std::mutex> its_socket_lock(socket_mutex_); + + // Check whether we need to wait (SOME/IP-TP separation time) + if (_entry.second > 0) { + if (last_sent_ != std::chrono::steady_clock::time_point()) { + const auto its_elapsed + = std::chrono::duration_cast<std::chrono::microseconds>( + std::chrono::steady_clock::now() - last_sent_).count(); + if (_entry.second > its_elapsed) + std::this_thread::sleep_for( + std::chrono::microseconds(_entry.second - its_elapsed)); + } + last_sent_ = std::chrono::steady_clock::now(); + } else { + last_sent_ = std::chrono::steady_clock::time_point(); + } + // Send + socket_->async_send( + boost::asio::buffer(*_entry.first), + std::bind( + &udp_client_endpoint_base_impl::send_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + _entry.first + ) + ); + } +} + +void udp_client_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + configuration_->get_configured_timing_requests(_service, + remote_address_.to_string(), remote_port_, _method, + _debouncing, _maximum_retention); +} + +void udp_client_endpoint_impl::receive() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (!socket_->is_open()) { + return; + } + message_buffer_ptr_t its_buffer = std::make_shared<message_buffer_t>(VSOMEIP_MAX_UDP_MESSAGE_SIZE); + socket_->async_receive_from( + boost::asio::buffer(*its_buffer), + const_cast<endpoint_type&>(remote_), + strand_.wrap( + std::bind( + &udp_client_endpoint_impl::receive_cbk, + std::dynamic_pointer_cast< + udp_client_endpoint_impl + >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + its_buffer + ) + ) + ); +} + +bool udp_client_endpoint_impl::get_remote_address( + boost::asio::ip::address &_address) const { + if (remote_address_.is_unspecified()) { + return false; + } + _address = remote_address_; + return true; +} + +std::uint16_t udp_client_endpoint_impl::get_local_port() const { + + uint16_t its_port(0); + + // Local port may be zero, if no client ports are configured + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_->is_open()) { + boost::system::error_code its_error; + endpoint_type its_local = socket_->local_endpoint(its_error); + if (!its_error) { + its_port = its_local.port(); + return its_port; + } + } + + return local_.port(); +} + +void udp_client_endpoint_impl::set_local_port() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::system::error_code its_error; + if (socket_->is_open()) { + endpoint_type its_endpoint = socket_->local_endpoint(its_error); + if (!its_error) { + local_.port(its_endpoint.port()); + } else { + VSOMEIP_WARNING << "udp_client_endpoint_impl::set_local_port() " + << "couldn't get local_endpoint: " << its_error.message(); + } + } else { + VSOMEIP_WARNING << "udp_client_endpoint_impl::set_local_port() " + << "failed to set port because the socket is not opened"; + } +} + +void udp_client_endpoint_impl::set_local_port(port_t _port) { + + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (!socket_->is_open()) { + local_.port(_port); + } else { + boost::system::error_code its_error; + endpoint_type its_endpoint = socket_->local_endpoint(its_error); + if (!its_error) + local_.port(its_endpoint.port()); + VSOMEIP_ERROR << "udp_client_endpoint_impl::set_local_port() " + << "Cannot change port on open socket!"; + } +} + +std::uint16_t udp_client_endpoint_impl::get_remote_port() const { + return remote_port_; +} + +void udp_client_endpoint_impl::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes, + const message_buffer_ptr_t& _recv_buffer) { + if (_error == boost::asio::error::operation_aborted) { + // endpoint was stopped + return; + } + std::shared_ptr<routing_host> its_host = routing_host_.lock(); + if (!_error && 0 < _bytes && its_host) { +#if 0 + std::stringstream msg; + msg << "ucei::rcb(" << _error.message() << "): "; + for (std::size_t i = 0; i < _bytes; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int) (*_recv_buffer)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::size_t remaining_bytes = _bytes; + std::size_t i = 0; + + do { + uint64_t read_message_size + = utility::get_message_size(&(*_recv_buffer)[i], + remaining_bytes); + if (read_message_size > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Message size exceeds allowed maximum!"; + return; + } + uint32_t current_message_size = static_cast<uint32_t>(read_message_size); + if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && + current_message_size <= remaining_bytes) { + if (remaining_bytes - current_message_size > remaining_bytes) { + VSOMEIP_ERROR << "buffer underflow in udp client endpoint ~> abort!"; + return; + } else if (current_message_size > VSOMEIP_RETURN_CODE_POS && + ((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION || + !utility::is_valid_message_type(tp::tp::tp_flag_unset((*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS])) || + !utility::is_valid_return_code(static_cast<return_code_e>((*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS])) + )) { + if ((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + VSOMEIP_ERROR << "uce: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*_recv_buffer)[i + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + // ensure to send back a message w/ wrong protocol version + its_host->on_message(&(*_recv_buffer)[i], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + } else if (!utility::is_valid_message_type(tp::tp::tp_flag_unset( + (*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS]))) { + VSOMEIP_ERROR << "uce: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + (*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS]))) { + VSOMEIP_ERROR << "uce: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t((*_recv_buffer)[i + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << get_address_port_remote(); + } + receive(); + return; + } else if (tp::tp::tp_flag_is_set((*_recv_buffer)[i + VSOMEIP_MESSAGE_TYPE_POS])) { + const auto res = tp_reassembler_->process_tp_message( + &(*_recv_buffer)[i], current_message_size, + remote_address_, remote_port_); + if (res.first) { + its_host->on_message(&res.second[0], + static_cast<std::uint32_t>(res.second.size()), + this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + } + } else { + its_host->on_message(&(*_recv_buffer)[i], current_message_size, + this, + false, + VSOMEIP_ROUTING_CLIENT, + nullptr, + remote_address_, + remote_port_); + } + remaining_bytes -= current_message_size; + } else { + VSOMEIP_ERROR << "Received a unreliable vSomeIP message with bad " + "length field. Message size: " << current_message_size + << " Bytes. From: " << remote_.address() << ":" + << remote_.port() << ". Dropping message."; + remaining_bytes = 0; + } + i += current_message_size; + } while (remaining_bytes > 0); + } + if (!_error) { + receive(); + } else { + if (_error == boost::asio::error::connection_refused) { + VSOMEIP_WARNING << "uce::receive_cbk: local: " << get_address_port_local() + << " remote: " << get_address_port_remote() + << " error: " << _error.message(); + std::shared_ptr<endpoint_host> its_ep_host = endpoint_host_.lock(); + its_ep_host->on_disconnect(shared_from_this()); + restart(false); + } else { + receive(); + } + } +} + +std::string udp_client_endpoint_impl::get_address_port_remote() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::asio::ip::address its_address; + if (get_remote_address(its_address)) { + its_address_port += its_address.to_string(); + } + its_address_port += ":"; + its_address_port += std::to_string(remote_port_); + return its_address_port; +} + +std::string udp_client_endpoint_impl::get_address_port_local() const { + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + if (socket_->is_open()) { + endpoint_type its_local_endpoint = socket_->local_endpoint(ec); + if (!ec) { + its_address_port += its_local_endpoint.address().to_string(ec); + its_address_port += ":"; + its_address_port.append(std::to_string(its_local_endpoint.port())); + } + } + return its_address_port; +} + +void udp_client_endpoint_impl::print_status() { + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + its_queue_size = queue_.size(); + its_data_size = queue_size_; + } + std::string local; + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + local = get_address_port_local(); + } + + VSOMEIP_INFO << "status uce: " << local << " -> " + << get_address_port_remote() + << " queue: " << std::dec << its_queue_size + << " data: " << std::dec << its_data_size; +} + +std::string udp_client_endpoint_impl::get_remote_information() const { + boost::system::error_code ec; + return remote_.address().to_string(ec) + ":" + + std::to_string(remote_.port()); +} + +void udp_client_endpoint_impl::send_cbk(boost::system::error_code const &_error, + std::size_t _bytes, const message_buffer_ptr_t &_sent_msg) { + (void)_bytes; + if (!_error) { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + if (queue_.size() > 0) { + queue_size_ -= queue_.front().first->size(); + queue_.pop_front(); + + update_last_departure(); + + if (queue_.empty()) + is_sending_ = false; + else { + auto its_entry = get_front(); + if (its_entry.first) { + send_queued(its_entry); + } + } + } + return; + } else if (_error == boost::asio::error::broken_pipe) { + state_ = cei_state_e::CLOSED; + bool stopping(false); + { + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + stopping = sending_blocked_; + if (stopping) { + queue_.clear(); + queue_size_ = 0; + } else { + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_sent_msg && _sent_msg->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_WARNING << "uce::send_cbk received error: " + << _error.message() << " (" << std::dec + << _error.value() << ") " << get_remote_information() + << " " << std::dec << queue_.size() + << " " << std::dec << queue_size_ << " (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_session << "]"; + } + } + if (!stopping) { + print_status(); + } + was_not_connected_ = true; + shutdown_and_close_socket(true); + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); + } else if (_error == boost::asio::error::not_connected + || _error == boost::asio::error::bad_descriptor + || _error == boost::asio::error::no_permission) { + state_ = cei_state_e::CLOSED; + if (_error == boost::asio::error::no_permission) { + VSOMEIP_WARNING << "uce::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information(); + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + queue_.clear(); + queue_size_ = 0; + } + was_not_connected_ = true; + shutdown_and_close_socket(true); + strand_.dispatch(std::bind(&client_endpoint_impl::connect, + this->shared_from_this())); + } else if (_error == boost::asio::error::operation_aborted) { + VSOMEIP_WARNING << "uce::send_cbk received error: " << _error.message(); + // endpoint was stopped + sending_blocked_ = true; + shutdown_and_close_socket(false); + } else if (_error == boost::system::errc::destination_address_required) { + VSOMEIP_WARNING << "uce::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information(); + was_not_connected_ = true; + } else { + if (state_ == cei_state_e::CONNECTING) { + VSOMEIP_WARNING << "uce::send_cbk endpoint is already restarting:" + << get_remote_information(); + } else { + state_ = cei_state_e::CONNECTING; + shutdown_and_close_socket(false); + std::shared_ptr<endpoint_host> its_host = endpoint_host_.lock(); + if (its_host) { + its_host->on_disconnect(shared_from_this()); + } + restart(true); + } + service_t its_service(0); + method_t its_method(0); + client_t its_client(0); + session_t its_session(0); + if (_sent_msg && _sent_msg->size() > VSOMEIP_SESSION_POS_MAX) { + its_service = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_CLIENT_POS_MIN]); + its_session = bithelper::read_uint16_be(&(*_sent_msg)[VSOMEIP_SESSION_POS_MIN]); + } + VSOMEIP_WARNING << "uce::send_cbk received error: " << _error.message() + << " (" << std::dec << _error.value() << ") " + << get_remote_information() << " " + << " " << std::dec << queue_.size() + << " " << std::dec << queue_size_ << " (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_session << "]"; + print_status(); + } + + std::lock_guard<std::recursive_mutex> its_lock(mutex_); + is_sending_ = false; +} + +bool udp_client_endpoint_impl::tp_segmentation_enabled( + service_t _service, instance_t _instance, method_t _method) const { + + return configuration_->is_tp_client(_service, _instance, _method); +} + +bool udp_client_endpoint_impl::is_reliable() const { + return false; +} + +std::uint32_t udp_client_endpoint_impl::get_max_allowed_reconnects() const { + return MAX_RECONNECTS_UNLIMITED; +} + +void udp_client_endpoint_impl::max_allowed_reconnects_reached() { + return; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_server_endpoint_impl.cpp new file mode 100644 index 00000000000..23675b4aade --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/udp_server_endpoint_impl.cpp @@ -0,0 +1,945 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <sstream> +#include <thread> + +#include <boost/asio/ip/multicast.hpp> +#include <boost/asio/ip/network_v4.hpp> +#include <boost/asio/ip/network_v6.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/endpoint_definition.hpp" +#include "../include/endpoint_host.hpp" +#include "../include/tp.hpp" +#include "../include/udp_server_endpoint_impl.hpp" +#include "../include/udp_server_endpoint_impl_receive_op.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../../service_discovery/include/defines.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" + +namespace ip = boost::asio::ip; + +namespace vsomeip_v3 { + +udp_server_endpoint_impl::udp_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + boost::asio::io_context& _io, const std::shared_ptr<configuration>& _configuration) : + server_endpoint_impl<ip::udp>(_endpoint_host, _routing_host, _io, _configuration), + unicast_recv_buffer_(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0), + is_v4_(false), multicast_id_(0), joined_group_(false), netmask_(_configuration->get_netmask()), + prefix_(_configuration->get_prefix()), + tp_reassembler_(std::make_shared<tp::tp_reassembler>( + _configuration->get_max_message_size_unreliable(), _io)), + tp_cleanup_timer_(_io), is_stopped_(true), on_unicast_sent_ {nullptr}, + receive_own_multicast_messages_(false), on_sent_multicast_received_ {nullptr} { + is_supporting_someip_tp_ = true; +} + +bool udp_server_endpoint_impl::is_local() const { + return false; +} + +void udp_server_endpoint_impl::init(const endpoint_type& _local, + boost::system::error_code& _error) { + + if (!unicast_socket_) { + unicast_socket_ = std::make_shared<socket_type>(io_, _local.protocol()); + if (!unicast_socket_) { + _error = boost::system::errc::make_error_code(boost::system::errc::not_enough_memory); + return; + } + } + + if (!unicast_socket_->is_open()) { + unicast_socket_->open(_local.protocol(), _error); + if (_error) + return; + } + + boost::asio::socket_base::reuse_address optionReuseAddress(true); + unicast_socket_->set_option(optionReuseAddress, _error); + if (_error) + return; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // If specified, bind to device + std::string its_device(configuration_->get_device()); + if (its_device != "") { + if (setsockopt(unicast_socket_->native_handle(), SOL_SOCKET, SO_BINDTODEVICE, + its_device.c_str(), static_cast<socklen_t>(its_device.size())) == -1) { + VSOMEIP_WARNING << "UDP Server: Could not bind to device \"" << its_device << "\""; + } + } +#endif + + unicast_socket_->bind(_local, _error); + if (_error) + return; + + if (_local.address().is_v4()) { + is_v4_ = true; + boost::asio::ip::multicast::outbound_interface option(_local.address().to_v4()); + unicast_socket_->set_option(option, _error); + if (_error) + return; + } else { + boost::asio::ip::multicast::outbound_interface option( + static_cast<unsigned int>(_local.address().to_v6().scope_id())); + unicast_socket_->set_option(option, _error); + if (_error) + return; + } + + boost::asio::socket_base::broadcast option(true); + unicast_socket_->set_option(option, _error); + if (_error) + return; + + const int its_udp_recv_buffer_size = configuration_->get_udp_receive_buffer_size(); + unicast_socket_->set_option(boost::asio::socket_base::receive_buffer_size( + static_cast<int>(its_udp_recv_buffer_size)), _error); + + if (_error) + return; + + boost::asio::socket_base::receive_buffer_size its_option; + unicast_socket_->get_option(its_option, _error); +#ifdef __linux__ + // If regular setting of the buffer size did not work, try to force + // (requires CAP_NET_ADMIN to be successful) + if (its_option.value() < 0 || its_option.value() < its_udp_recv_buffer_size) { + _error.assign(setsockopt(unicast_socket_->native_handle(), SOL_SOCKET, SO_RCVBUFFORCE, + &its_udp_recv_buffer_size, sizeof(its_udp_recv_buffer_size)), + boost::system::generic_category()); + if (!_error) { + VSOMEIP_INFO << "udp_server_endpoint_impl: SO_RCVBUFFORCE successful."; + } + unicast_socket_->get_option(its_option, _error); + } +#endif + if (_error) + return; + + local_ = _local; + local_port_ = _local.port(); + + this->max_message_size_ = VSOMEIP_MAX_UDP_MESSAGE_SIZE; + this->queue_limit_ = configuration_->get_endpoint_queue_limit( + configuration_->get_unicast_address().to_string(), + local_port_); +} + +void udp_server_endpoint_impl::start() { + is_stopped_ = false; + receive(); +} + +void udp_server_endpoint_impl::stop() { + server_endpoint_impl::stop(); + is_stopped_ = true; + + { + std::scoped_lock its_lock {unicast_mutex_}; + + if (unicast_socket_->is_open()) { + boost::system::error_code its_error; + unicast_socket_->cancel(its_error); + } + } + + { + std::scoped_lock its_lock {multicast_mutex_}; + if (multicast_socket_ && multicast_socket_->is_open()) { + boost::system::error_code its_error; + multicast_socket_->cancel(its_error); + } + + for (auto& its_joined_address : joined_) + its_joined_address.second = false; + } + + tp_reassembler_->stop(); +} + +void udp_server_endpoint_impl::shutdown_and_close() { + { + std::lock_guard<std::mutex> its_lock(unicast_mutex_); + unicast_shutdown_and_close_unlocked(); + } + + { + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + multicast_shutdown_and_close_unlocked(); + } +} + +void udp_server_endpoint_impl::unicast_shutdown_and_close_unlocked() { + boost::system::error_code its_error; + unicast_socket_->shutdown(socket_type::shutdown_both, its_error); + unicast_socket_->close(its_error); +} + +void udp_server_endpoint_impl::multicast_shutdown_and_close_unlocked() { + if (!multicast_socket_) { + return; + } + boost::system::error_code its_error; + multicast_socket_->shutdown(socket_type::shutdown_both, its_error); + multicast_socket_->close(its_error); +} + +void udp_server_endpoint_impl::receive() { + receive_unicast(); +} + +void udp_server_endpoint_impl::receive_unicast() { + + std::lock_guard<std::mutex> its_lock(unicast_mutex_); + + if (unicast_socket_->is_open()) { + unicast_socket_->async_receive_from( + boost::asio::buffer(&unicast_recv_buffer_[0], max_message_size_), + unicast_remote_, + std::bind( + &udp_server_endpoint_impl::on_unicast_received, + std::dynamic_pointer_cast< + udp_server_endpoint_impl >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +// +// receive_multicast is called with multicast_mutex_ being hold +// +void udp_server_endpoint_impl::receive_multicast(uint8_t _multicast_id) { + + if (_multicast_id == multicast_id_ && multicast_socket_ && multicast_socket_->is_open()) { + auto its_storage = std::make_shared<udp_endpoint_receive_op::storage>( + multicast_mutex_, + multicast_socket_, + multicast_remote_, + std::bind( + &udp_server_endpoint_impl::on_multicast_received, + std::dynamic_pointer_cast< + udp_server_endpoint_impl >(shared_from_this()), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4 + ), + &multicast_recv_buffer_[0], + max_message_size_, + _multicast_id, + is_v4_, + boost::asio::ip::address(), + std::numeric_limits<std::size_t>::min() + ); + multicast_socket_->async_wait(socket_type::wait_read, udp_endpoint_receive_op::receive_cb(its_storage)); + } +} + +bool udp_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + std::lock_guard<std::mutex> its_lock(mutex_); + endpoint_type its_target(_target->get_address(), _target->get_port()); + return send_intern(its_target, _data, _size); +} + +bool udp_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + bool ret(false); + std::lock_guard<std::mutex> its_lock(mutex_); + const endpoint_type its_target(_target->get_address(), _target->get_port()); + const auto its_target_iterator(find_or_create_target_unlocked(its_target)); + auto& its_data = its_target_iterator->second; + + if (check_message_size(nullptr, _size, its_target) == endpoint_impl::cms_ret_e::MSG_OK && + check_queue_limit(_data, _size, its_data)) { + its_data.queue_.emplace_back( + std::make_pair(std::make_shared<message_buffer_t>(_data, _data + _size), 0)); + its_data.queue_size_ += _size; + + if (!its_data.is_sending_) { // no writing in progress + (void)send_queued(its_target_iterator); + } + ret = true; + } + return ret; +} + +bool udp_server_endpoint_impl::send_queued( + const target_data_iterator_type _it) { + + std::lock_guard<std::mutex> its_last_sent_lock(last_sent_mutex_); + std::lock_guard<std::mutex> its_unicast_lock(unicast_mutex_); + + const auto its_entry = _it->second.queue_.front(); +#if 0 + std::stringstream msg; + msg << "usei::sq(" << _queue_iterator->first.address().to_string() << ":" + << _queue_iterator->first.port() << "): "; + for (std::size_t i = 0; i < its_buffer->size(); ++i) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int)(*its_entry.first)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + // Check whether we need to wait (SOME/IP-TP separation time) + if (its_entry.second > 0) { + if (last_sent_ != std::chrono::steady_clock::time_point()) { + const auto its_elapsed + = std::chrono::duration_cast<std::chrono::microseconds>( + std::chrono::steady_clock::now() - last_sent_).count(); + if (its_entry.second > its_elapsed) + std::this_thread::sleep_for( + std::chrono::microseconds(its_entry.second - its_elapsed)); + } + last_sent_ = std::chrono::steady_clock::now(); + } else { + last_sent_ = std::chrono::steady_clock::time_point(); + } + + _it->second.is_sending_ = true; + unicast_socket_->async_send_to( + boost::asio::buffer(*its_entry.first), _it->first, + [this, _it, its_entry](boost::system::error_code const& _error, std::size_t _bytes) { + if (!_error && on_unicast_sent_ && !_it->first.address().is_multicast()) { + on_unicast_sent_(&(its_entry.first)->at(0), static_cast<uint32_t>(_bytes), + _it->first.address()); + } + send_cbk(_it->first, _error, _bytes); + }); + return false; +} + +void udp_server_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, method_t _method, + std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + + configuration_->get_configured_timing_responses(_service, + udp_server_endpoint_base_impl::local_.address().to_string(), + udp_server_endpoint_base_impl::local_.port(), _method, + _debouncing, _maximum_retention); +} + +// +// Both is_joined - methods must be called with multicast_mutex_ being hold! +// +bool udp_server_endpoint_impl::is_joined(const std::string &_address) const { + + return (joined_.find(_address) != joined_.end()); +} + +bool udp_server_endpoint_impl::is_joined( + const std::string &_address, bool& _received) const { + + const auto found_address = joined_.find(_address); + if (found_address != joined_.end()) { + _received = found_address->second; + } else { + _received = false; + } + + return (found_address != joined_.end()); +} + +void udp_server_endpoint_impl::join(const std::string &_address) { + + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + join_unlocked(_address); +} + +void udp_server_endpoint_impl::join_unlocked(const std::string &_address) { + + bool has_received(false); + + // + // join_func must be called with multicast_mutex_ being hold! + // + auto join_func = [this](const std::string &_address) { + try { + VSOMEIP_DEBUG << "Joining to multicast group " << _address + << " from " << local_.address().to_string(); + + auto its_endpoint_host = endpoint_host_.lock(); + if (its_endpoint_host) { + multicast_option_t its_join_option { shared_from_this(), true, + boost::asio::ip::make_address(_address) }; + its_endpoint_host->add_multicast_option(its_join_option); + } + + joined_[_address] = false; + } catch (const std::exception &e) { + VSOMEIP_ERROR << "udp_server_endpoint_impl::join" << ":" << e.what() + << " address: " << _address; + } + }; + + if (!is_joined(_address, has_received)) { + join_func(_address); + } else if (!has_received) { + // joined the multicast group but didn't receive a event yet -> rejoin + leave_unlocked(_address); + join_func(_address); + } +} + +void udp_server_endpoint_impl::leave(const std::string &_address) { + + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + leave_unlocked(_address); +} + +void udp_server_endpoint_impl::leave_unlocked(const std::string &_address) { + + try { + if (is_joined(_address)) { + VSOMEIP_DEBUG << "Leaving the multicast group " << _address + << " from " << local_.address().to_string(); + + if (multicast_socket_) { + auto its_endpoint_host = endpoint_host_.lock(); + if (its_endpoint_host) { + multicast_option_t its_leave_option { shared_from_this(), + false, boost::asio::ip::make_address(_address) }; + its_endpoint_host->add_multicast_option(its_leave_option); + } + } + + joined_.erase(_address); + } + } + catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << ":" << e.what() + << " address: " << _address; + } +} + +void udp_server_endpoint_impl::add_default_target( + service_t _service, const std::string &_address, uint16_t _port) { + std::lock_guard<std::mutex> its_lock(default_targets_mutex_); + endpoint_type its_endpoint( + boost::asio::ip::address::from_string(_address), _port); + default_targets_[_service] = its_endpoint; +} + +void udp_server_endpoint_impl::remove_default_target(service_t _service) { + std::lock_guard<std::mutex> its_lock(default_targets_mutex_); + default_targets_.erase(_service); +} + +bool udp_server_endpoint_impl::get_default_target(service_t _service, + udp_server_endpoint_impl::endpoint_type &_target) const { + std::lock_guard<std::mutex> its_lock(default_targets_mutex_); + bool is_valid(false); + auto find_service = default_targets_.find(_service); + if (find_service != default_targets_.end()) { + _target = find_service->second; + is_valid = true; + } + return is_valid; +} + +std::uint16_t udp_server_endpoint_impl::get_local_port() const { + return local_port_; +} + +void udp_server_endpoint_impl::set_local_port(std::uint16_t _port) { + (void)_port; +} + +void udp_server_endpoint_impl::on_unicast_received( + boost::system::error_code const &_error, + std::size_t _bytes) { + + if (is_stopped_ + || _error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset) { + shutdown_and_close(); + } else if (_error != boost::asio::error::operation_aborted) { + { + // By locking the multicast mutex here it is ensured that unicast + // & multicast messages are not processed in parallel. This aligns + // the behavior of endpoints with one and two active sockets. + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + on_message_received(_error, _bytes, false, + unicast_remote_, unicast_recv_buffer_); + } + receive_unicast(); + } +} + +void udp_server_endpoint_impl::on_multicast_received( + boost::system::error_code const &_error, + std::size_t _bytes, + uint8_t _multicast_id, + const boost::asio::ip::address &_destination) { + + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + if (is_stopped_ + || _error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset) { + shutdown_and_close(); + } else if (_error != boost::asio::error::operation_aborted) { + + if (multicast_remote_.address() != local_.address()) { + if (is_same_subnet(multicast_remote_.address())) { + auto find_joined = joined_.find(_destination.to_string()); + if (find_joined != joined_.end()) + find_joined->second = true; + + on_message_received(_error, _bytes, true, multicast_remote_, + multicast_recv_buffer_); + } + } else if (receive_own_multicast_messages_ && on_sent_multicast_received_) { + on_sent_multicast_received_(&multicast_recv_buffer_[0], static_cast<uint32_t>(_bytes), + boost::asio::ip::address()); + } + + receive_multicast(_multicast_id); + } +} + +void udp_server_endpoint_impl::on_message_received( + boost::system::error_code const &_error, std::size_t _bytes, + bool _is_multicast, + endpoint_type const &_remote, + message_buffer_t const &_buffer) { +#if 0 + std::stringstream msg; + msg << "usei::rcb(" << _error.message() << "): "; + for (std::size_t i = 0; i < _bytes; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') + << (int) _buffer[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::shared_ptr<routing_host> its_host = routing_host_.lock(); + + if (its_host) { + if (!_error && 0 < _bytes) { + std::size_t remaining_bytes = _bytes; + std::size_t i = 0; + const boost::asio::ip::address its_remote_address(_remote.address()); + const std::uint16_t its_remote_port(_remote.port()); + do { + uint64_t read_message_size + = utility::get_message_size(&_buffer[i], + remaining_bytes); + if (read_message_size > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Message size exceeds allowed maximum!"; + return; + } + uint32_t current_message_size = static_cast<uint32_t>(read_message_size); + if (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && + current_message_size <= remaining_bytes) { + if (remaining_bytes - current_message_size > remaining_bytes) { + VSOMEIP_ERROR << "buffer underflow in udp client endpoint ~> abort!"; + return; + } else if (current_message_size > VSOMEIP_RETURN_CODE_POS && + (_buffer[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION || + !utility::is_valid_message_type(tp::tp::tp_flag_unset(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS])) || + !utility::is_valid_return_code(static_cast<return_code_e>(_buffer[i + VSOMEIP_RETURN_CODE_POS])) || + (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS]) && get_local_port() == configuration_->get_sd_port()) + )) { + if (_buffer[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + VSOMEIP_ERROR << "use: Wrong protocol version: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(_buffer[i + VSOMEIP_PROTOCOL_VERSION_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + // ensure to send back a message w/ wrong protocol version + its_host->on_message(&_buffer[i], + VSOMEIP_SOMEIP_HEADER_SIZE + 8, this, + _is_multicast, + VSOMEIP_ROUTING_CLIENT, + nullptr, + its_remote_address, its_remote_port); + } else if (!utility::is_valid_message_type(tp::tp::tp_flag_unset( + _buffer[i + VSOMEIP_MESSAGE_TYPE_POS]))) { + VSOMEIP_ERROR << "use: Invalid message type: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } else if (!utility::is_valid_return_code(static_cast<return_code_e>( + _buffer[i + VSOMEIP_RETURN_CODE_POS]))) { + VSOMEIP_ERROR << "use: Invalid return code: 0x" + << std::hex << std::setw(2) << std::setfill('0') + << std::uint32_t(_buffer[i + VSOMEIP_RETURN_CODE_POS]) + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } else if (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS]) + && get_local_port() == configuration_->get_sd_port()) { + VSOMEIP_WARNING << "use: Received a SomeIP/TP message on SD port:" + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } + return; + } + remaining_bytes -= current_message_size; + const service_t its_service = bithelper::read_uint16_be(&_buffer[i + VSOMEIP_SERVICE_POS_MIN]); + + if (utility::is_request( + _buffer[i + VSOMEIP_MESSAGE_TYPE_POS])) { + const client_t its_client = bithelper::read_uint16_be(&_buffer[i + VSOMEIP_CLIENT_POS_MIN]); + if (its_client != MAGIC_COOKIE_CLIENT) { + const session_t its_session = bithelper::read_uint16_be(&_buffer[i + VSOMEIP_SESSION_POS_MIN]); + clients_mutex_.lock(); + clients_[its_client][its_session] = _remote; + clients_mutex_.unlock(); + } + } + if (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS])) { + const method_t its_method = bithelper::read_uint16_be(&_buffer[i + VSOMEIP_METHOD_POS_MIN]); + instance_t its_instance = this->get_instance(its_service); + + if (its_instance != ANY_INSTANCE) { + if (!tp_segmentation_enabled(its_service, its_instance, its_method)) { + VSOMEIP_WARNING << "use: Received a SomeIP/TP message for service: 0x" << std::hex << its_service + << " method: 0x" << its_method << " which is not configured for TP:" + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + return; + } + } + const auto res = tp_reassembler_->process_tp_message( + &_buffer[i], current_message_size, + its_remote_address, its_remote_port); + if (res.first) { + if (utility::is_request(res.second[VSOMEIP_MESSAGE_TYPE_POS])) { + const client_t its_client = bithelper::read_uint16_be(&res.second[VSOMEIP_CLIENT_POS_MIN]); + if (its_client != MAGIC_COOKIE_CLIENT) { + const session_t its_session = bithelper::read_uint16_be(&res.second[VSOMEIP_SESSION_POS_MIN]); + std::lock_guard<std::mutex> its_client_lock(clients_mutex_); + clients_[its_client][its_session] = _remote; + } + } + its_host->on_message(&res.second[0], + static_cast<std::uint32_t>(res.second.size()), + this, _is_multicast, VSOMEIP_ROUTING_CLIENT, + nullptr, + its_remote_address, its_remote_port); + } + } else { + if (its_service != VSOMEIP_SD_SERVICE || + (current_message_size > VSOMEIP_SOMEIP_HEADER_SIZE && + current_message_size >= remaining_bytes)) { + its_host->on_message(&_buffer[i], + current_message_size, this, _is_multicast, + VSOMEIP_ROUTING_CLIENT, + nullptr, + its_remote_address, its_remote_port); + } else { + //ignore messages for service discovery with shorter SomeIP length + VSOMEIP_ERROR << "Received an unreliable vSomeIP SD message with too short length field" + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + } + } + i += current_message_size; + } else { + VSOMEIP_ERROR << "Received an unreliable vSomeIP message with bad length field" + << " local: " << get_address_port_local() + << " remote: " << its_remote_address << ":" << std::dec << its_remote_port; + if (remaining_bytes > VSOMEIP_SERVICE_POS_MAX) { + service_t its_service = bithelper::read_uint16_be(&_buffer[VSOMEIP_SERVICE_POS_MIN]); + if (its_service != VSOMEIP_SD_SERVICE) { + if (read_message_size == 0) { + VSOMEIP_ERROR << "Ignoring unreliable vSomeIP message with SomeIP message length 0!"; + } else { + auto its_endpoint_host = endpoint_host_.lock(); + if (its_endpoint_host) { + its_endpoint_host->on_error(&_buffer[i], + (uint32_t)remaining_bytes, this, + its_remote_address, its_remote_port); + } + } + } + } + remaining_bytes = 0; + } + } while (remaining_bytes > 0); + } + } +} + +bool udp_server_endpoint_impl::is_same_subnet(const boost::asio::ip::address &_address) const { + bool is_same(true); + + if (_address.is_v4()) { + boost::asio::ip::network_v4 its_network(local_.address().to_v4(), netmask_.to_v4()); + boost::asio::ip::address_v4_range its_hosts = its_network.hosts(); + is_same = (its_hosts.find(_address.to_v4()) != its_hosts.end()); + } else { + boost::asio::ip::network_v6 its_network(local_.address().to_v6(), prefix_); + boost::asio::ip::address_v6_range its_hosts = its_network.hosts(); + is_same = (its_hosts.find(_address.to_v6()) != its_hosts.end()); + } + + return is_same; +} + +void udp_server_endpoint_impl::print_status() { + std::lock_guard<std::mutex> its_lock(mutex_); + + VSOMEIP_INFO << "status use: " << std::dec << local_port_ + << " number targets: " << std::dec << targets_.size() + << " recv_buffer: " + << std::dec << unicast_recv_buffer_.capacity() + << " multicast_recv_buffer: " + << std::dec << multicast_recv_buffer_.capacity(); + + for (const auto &c : targets_) { + std::size_t its_data_size(0); + std::size_t its_queue_size(0); + its_queue_size = c.second.queue_.size(); + its_data_size = c.second.queue_size_; + + boost::system::error_code ec; + VSOMEIP_INFO << "status use: client: " + << c.first.address().to_string(ec) << ":" + << std::dec << c.first.port() + << " queue: " << std::dec << its_queue_size + << " data: " << std::dec << its_data_size; + } +} + +std::string udp_server_endpoint_impl::get_remote_information( + const target_data_iterator_type _it) const { + + boost::system::error_code ec; + return _it->first.address().to_string(ec) + ":" + + std::to_string(_it->first.port()); +} + +std::string udp_server_endpoint_impl::get_remote_information( + const endpoint_type& _remote) const { + + boost::system::error_code ec; + return _remote.address().to_string(ec) + ":" + + std::to_string(_remote.port()); +} + +bool udp_server_endpoint_impl::is_reliable() const { + return false; +} + +std::string udp_server_endpoint_impl::get_address_port_local() const { + + std::lock_guard<std::mutex> its_lock(unicast_mutex_); + std::string its_address_port; + its_address_port.reserve(21); + boost::system::error_code ec; + if (unicast_socket_->is_open()) { + endpoint_type its_local_endpoint = unicast_socket_->local_endpoint(ec); + if (!ec) { + its_address_port += its_local_endpoint.address().to_string(ec); + its_address_port += ":"; + its_address_port += std::to_string(its_local_endpoint.port()); + } + } + return its_address_port; +} + +bool udp_server_endpoint_impl::tp_segmentation_enabled( + service_t _service, instance_t _instance, method_t _method) const { + + return configuration_->is_tp_service(_service, _instance, _method); +} + +void +udp_server_endpoint_impl::set_multicast_option(const boost::asio::ip::address& _address, + bool _is_join, boost::system::error_code &_error) { + std::scoped_lock its_lock {multicast_mutex_}; + if (_is_join) { + // If the multicast socket does not yet exist, create it. + if (!multicast_socket_) { + multicast_socket_ = std::make_unique<socket_type>(io_, local_.protocol()); + if (!multicast_socket_) { + _error = boost::system::errc::make_error_code(boost::system::errc::not_enough_memory); + return; + } + } + + // If the multicast socket is not yet open, open it. + if (!multicast_socket_->is_open()) { + multicast_socket_->open(local_.protocol(), _error); + if (_error) { + return; + } + } + + multicast_socket_->set_option(ip::udp::socket::reuse_address(true), _error); + if (_error) { + return; + } + +#ifdef _WIN32 + const char *its_pktinfo_option("0001"); + ::setsockopt(multicast_socket_->native_handle(), + (is_v4_ ? IPPROTO_IP : IPPROTO_IPV6), + (is_v4_ ? IP_PKTINFO : IPV6_PKTINFO), + its_pktinfo_option, sizeof(its_pktinfo_option)); +#else + int its_pktinfo_option(1); + ::setsockopt(multicast_socket_->native_handle(), + (is_v4_ ? IPPROTO_IP : IPPROTO_IPV6), + (is_v4_ ? IP_PKTINFO : IPV6_RECVPKTINFO), + &its_pktinfo_option, sizeof(its_pktinfo_option)); +#endif + if (multicast_recv_buffer_.empty()) + multicast_recv_buffer_.resize(VSOMEIP_MAX_UDP_MESSAGE_SIZE, 0); + + if (!multicast_local_) { + if (is_v4_) { + multicast_local_ = std::make_unique<endpoint_type> + (boost::asio::ip::address_v4::any(), local_port_); + } else { // is_v6 + multicast_local_ = std::make_unique<endpoint_type> + (boost::asio::ip::address_v6::any(), local_port_); + } + } + + multicast_socket_->bind(*multicast_local_, _error); + if (_error) { + return; + } + + const int its_udp_recv_buffer_size = + configuration_->get_udp_receive_buffer_size(); + + multicast_socket_->set_option(boost::asio::socket_base::receive_buffer_size( + its_udp_recv_buffer_size), _error); + if (_error) { + return; + } +#ifndef _WIN32 + // define socket timeout + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = VSOMEIP_SETSOCKOPT_TIMEOUT_US; + + if (setsockopt( + multicast_socket_->native_handle(), + SOL_SOCKET, SO_RCVTIMEO, + &timeout, sizeof(timeout)) == -1) { + VSOMEIP_WARNING << __func__ + << ": unable to setsockopt SO_RCVTIMEO"; + } + + if (setsockopt( + multicast_socket_->native_handle(), + SOL_SOCKET, SO_SNDTIMEO, + &timeout, sizeof(timeout)) == -1) { + VSOMEIP_WARNING << __func__ + << ": unable to setsockopt SO_SNDTIMEO"; + } +#endif + boost::asio::socket_base::receive_buffer_size its_option; + multicast_socket_->get_option(its_option, _error); + if (_error) { + return; + } +#ifdef __linux__ + // If regular setting of the buffer size did not work, try to force + // (requires CAP_NET_ADMIN to be successful) + if (its_option.value() < 0 + || its_option.value() < its_udp_recv_buffer_size) { + _error.assign(setsockopt(multicast_socket_->native_handle(), + SOL_SOCKET, SO_RCVBUFFORCE, + &its_udp_recv_buffer_size, sizeof(its_udp_recv_buffer_size)), + boost::system::generic_category()); + if (!_error) { + VSOMEIP_INFO << "udp_server_endpoint_impl<multicast>: " + << "SO_RCVBUFFORCE: successful."; + } + multicast_socket_->get_option(its_option, _error); + if (_error) { + return; + } + } +#endif + VSOMEIP_INFO << "udp_server_endpoint_impl<multicast>: SO_RCVBUF is: " + << std::dec << its_option.value() + << " (" << its_udp_recv_buffer_size << ") local port:" + << std::dec << local_port_; + + multicast_id_++; + receive_multicast(multicast_id_); + + boost::asio::ip::multicast::join_group its_join_option; + { + std::lock_guard<std::mutex> its_lock(local_mutex_); + if (is_v4_) { + its_join_option = boost::asio::ip::multicast::join_group( + _address.to_v4(), + local_.address().to_v4()); + } else { + its_join_option = boost::asio::ip::multicast::join_group( + _address.to_v6(), + static_cast<unsigned int>(local_.address().to_v6().scope_id())); + } + } + multicast_socket_->set_option(its_join_option, _error); + + if (!_error) { + std::lock_guard<std::recursive_mutex> its_guard(multicast_mutex_); + joined_[_address.to_string()] = false; + joined_group_ = true; + } + } else if (multicast_socket_ && multicast_socket_->is_open()) { + boost::asio::ip::multicast::leave_group its_leave_option(_address); + multicast_socket_->set_option(its_leave_option, _error); + + if (!_error) { + joined_.erase(_address.to_string()); + + if (0 == joined_.size()) { + joined_group_ = false; + + multicast_socket_->cancel(_error); + + multicast_socket_.reset(); + multicast_local_.reset(nullptr); + } + } + } +} + +void udp_server_endpoint_impl::set_unicast_sent_callback(const on_unicast_sent_cbk_t& _cbk) { + on_unicast_sent_ = _cbk; +} + +void udp_server_endpoint_impl::set_sent_multicast_received_callback( + const on_sent_multicast_received_cbk_t& _cbk) { + on_sent_multicast_received_ = _cbk; +} + +void udp_server_endpoint_impl::set_receive_own_multicast_messages(bool value) { + receive_own_multicast_messages_ = value; +} + +bool udp_server_endpoint_impl::is_joining() const { + + std::lock_guard<std::recursive_mutex> its_lock(multicast_mutex_); + return !joined_.empty(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/virtual_server_endpoint_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/virtual_server_endpoint_impl.cpp new file mode 100644 index 00000000000..1ed82396408 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/endpoints/src/virtual_server_endpoint_impl.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/virtual_server_endpoint_impl.hpp" + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { + +virtual_server_endpoint_impl::virtual_server_endpoint_impl(const std::string& _address, + uint16_t _port, bool _reliable, + boost::asio::io_context& _io) : + + address_(_address), + port_(_port), reliable_(_reliable), io_(_io) { } + +virtual_server_endpoint_impl::~virtual_server_endpoint_impl() { +} + +void virtual_server_endpoint_impl::start() { +} + +void virtual_server_endpoint_impl::prepare_stop(const endpoint::prepare_stop_handler_t &_handler, + service_t _service) { + (void)_service; + + auto ptr = shared_from_this(); + io_.post([ptr, _handler]() { _handler(ptr); }); +} + +void virtual_server_endpoint_impl::stop() { +} + +bool virtual_server_endpoint_impl::is_established() const { + return false; +} + +bool virtual_server_endpoint_impl::is_established_or_connected() const { + return false; +} + +void virtual_server_endpoint_impl::set_established(bool _established) { + (void) _established; +} + +void virtual_server_endpoint_impl::set_connected(bool _connected) { + (void) _connected; +} + +bool virtual_server_endpoint_impl::send(const byte_t *_data, uint32_t _size) { + (void)_data; + (void)_size; + return false; +} + +bool virtual_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool virtual_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + (void)_target; + (void)_data; + (void)_size; + return false; +} + + +void virtual_server_endpoint_impl::enable_magic_cookies() { +} + +void virtual_server_endpoint_impl::receive() { +} + +void virtual_server_endpoint_impl::add_default_target( + service_t _service, + const std::string &_address, uint16_t _port) { + (void)_service; + (void)_address; + (void)_port; +} + +void virtual_server_endpoint_impl::remove_default_target( + service_t _service) { + (void)_service; +} + +void virtual_server_endpoint_impl::remove_stop_handler( + service_t) { +} + +bool virtual_server_endpoint_impl::get_remote_address( + boost::asio::ip::address &_address) const { + (void)_address; + return false; +} + +std::uint16_t virtual_server_endpoint_impl::get_local_port() const { + return port_; +} + +void virtual_server_endpoint_impl::set_local_port(std::uint16_t _port) { + port_ = _port; +} + +std::uint16_t virtual_server_endpoint_impl::get_remote_port() const { + return ILLEGAL_PORT; +} + +bool virtual_server_endpoint_impl::is_reliable() const { + return reliable_; +} + +bool virtual_server_endpoint_impl::is_local() const { + return true; +} + +void virtual_server_endpoint_impl::restart(bool _force) { + (void)_force; +} + +void virtual_server_endpoint_impl::register_error_handler( + const error_handler_t &_handler) { + (void)_handler; +} + +void virtual_server_endpoint_impl::print_status() { + +} + +size_t virtual_server_endpoint_impl::get_queue_size() const { + return 0; +} +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/include/logger_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/include/logger_impl.hpp new file mode 100644 index 00000000000..3ca6bebb97d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/include/logger_impl.hpp @@ -0,0 +1,75 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOGGER_CONFIGURATION_HPP_ +#define VSOMEIP_V3_LOGGER_CONFIGURATION_HPP_ + +#include <memory> +#include <mutex> +#include <atomic> + +#ifdef USE_DLT +#ifndef ANDROID +#include <dlt/dlt.h> +#endif +#endif + +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { + +class configuration; + +namespace logger { + +class logger_impl { +public: + VSOMEIP_IMPORT_EXPORT static void init(const std::shared_ptr<configuration> &_configuration); + static std::shared_ptr<logger_impl> get(); + + logger_impl() = default; + ~logger_impl(); + + void set_configuration(const std::shared_ptr<configuration>& _configuration); + level_e get_loglevel() const; + bool has_console_log() const; + bool has_dlt_log() const; + bool has_file_log() const; + std::string get_logfile() const; + + const std::string& get_app_name() const; + std::unique_lock<std::mutex> get_app_name_lock() const; + +#ifdef USE_DLT + void log(level_e _level, const char* _data); + void register_context(const std::string& _context_id); + +private: + void enable_dlt(const std::string& _application, const std::string& _context); +#endif + +private: + static std::mutex mutex__; + static std::string app_name__; + + mutable std::mutex configuration_mutex_; + std::atomic<level_e> cfg_level {level_e::LL_NONE}; + std::atomic_bool cfg_console_enabled {false}; + std::atomic_bool cfg_dlt_enabled {false}; + std::atomic_bool cfg_file_enabled {false}; + std::string cfg_file_name {""}; + +#ifdef USE_DLT +#ifndef ANDROID + std::mutex dlt_context_mutex_; + DLT_DECLARE_CONTEXT(dlt_) +#endif +#endif +}; + +} // namespace logger +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_LOGGER_CONFIGURATION_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/logger_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/logger_impl.cpp new file mode 100644 index 00000000000..d403500c122 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/logger_impl.cpp @@ -0,0 +1,169 @@ +// Copyright (C) 2020-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iostream> + +#include <vsomeip/runtime.hpp> + +#include "../include/logger_impl.hpp" +#include "../../configuration/include/configuration.hpp" + +namespace vsomeip_v3 { +namespace logger { + +std::mutex logger_impl::mutex__; +std::string logger_impl::app_name__; + +void +logger_impl::init(const std::shared_ptr<configuration> &_configuration) { + std::scoped_lock its_lock {mutex__}; + auto its_logger = logger_impl::get(); + its_logger->set_configuration(_configuration); + + const char *its_name = getenv(VSOMEIP_ENV_APPLICATION_NAME); + app_name__ = (nullptr != its_name) ? its_name : ""; + +#ifdef USE_DLT +# define VSOMEIP_LOG_DEFAULT_CONTEXT_ID "VSIP" +# define VSOMEIP_LOG_DEFAULT_CONTEXT_NAME "vSomeIP context" + +#ifndef ANDROID + std::string its_context_id = runtime::get_property("LogContext"); + if (its_context_id == "") + its_context_id = VSOMEIP_LOG_DEFAULT_CONTEXT_ID; + its_logger->register_context(its_context_id); +#endif +#endif +} + +logger_impl::~logger_impl() { +#ifdef USE_DLT +#ifndef ANDROID + DLT_UNREGISTER_CONTEXT(dlt_); +#endif +#endif +} + +level_e logger_impl::get_loglevel() const { + return cfg_level; +} + +bool logger_impl::has_console_log() const { + return cfg_console_enabled; +} + +bool logger_impl::has_dlt_log() const { + return cfg_dlt_enabled; +} + +bool logger_impl::has_file_log() const { + return cfg_file_enabled; +} + +std::string logger_impl::get_logfile() const { + std::scoped_lock its_lock {configuration_mutex_}; + return cfg_file_name; +} + +const std::string& logger_impl::get_app_name() const { + return app_name__; +} + +std::unique_lock<std::mutex> logger_impl::get_app_name_lock() const { + std::unique_lock its_lock(mutex__); + return its_lock; +} + +void logger_impl::set_configuration(const std::shared_ptr<configuration>& _configuration) { + + std::scoped_lock its_lock {configuration_mutex_}; + if (_configuration) { + cfg_level = _configuration->get_loglevel(); + cfg_console_enabled = _configuration->has_console_log(); + cfg_dlt_enabled = _configuration->has_dlt_log(); + cfg_file_enabled = _configuration->has_file_log(); + cfg_file_name = _configuration->get_logfile(); + } +} + +#ifdef USE_DLT +#ifndef ANDROID +void +logger_impl::log(level_e _level, const char *_data) { + + // Prepare log level + DltLogLevelType its_level; + switch (_level) { + case level_e::LL_FATAL: + its_level = DLT_LOG_FATAL; + break; + case level_e::LL_ERROR: + its_level = DLT_LOG_ERROR; + break; + case level_e::LL_WARNING: + its_level = DLT_LOG_WARN; + break; + case level_e::LL_INFO: + its_level = DLT_LOG_INFO; + break; + case level_e::LL_DEBUG: + its_level = DLT_LOG_DEBUG; + break; + case level_e::LL_VERBOSE: + its_level = DLT_LOG_VERBOSE; + break; + default: + its_level = DLT_LOG_DEFAULT; + }; + + std::scoped_lock its_lock {dlt_context_mutex_}; + DLT_LOG_STRING(dlt_, its_level, _data); +} + +void logger_impl::register_context(const std::string& _context_id) { + std::scoped_lock its_lock {dlt_context_mutex_}; + DLT_REGISTER_CONTEXT(dlt_, _context_id.c_str(), VSOMEIP_LOG_DEFAULT_CONTEXT_NAME); +} +#endif +#endif + +static std::shared_ptr<logger_impl> *the_logger_ptr__(nullptr); +static std::mutex the_logger_mutex__; + +std::shared_ptr<logger_impl> +logger_impl::get() { +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + std::scoped_lock its_lock {the_logger_mutex__}; +#endif + if (the_logger_ptr__ == nullptr) { + the_logger_ptr__ = new std::shared_ptr<logger_impl>(); + } + if (the_logger_ptr__ != nullptr) { + if (!(*the_logger_ptr__)) { + *the_logger_ptr__ = std::make_shared<logger_impl>(); + } + return *the_logger_ptr__; + } + return nullptr; +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +static void logger_impl_teardown(void) __attribute__((destructor)); +static void logger_impl_teardown(void) +{ + // TODO: This mutex is causing a crash due to changes in the way mutexes are defined. + // Since this function only runs on the main thread, no mutex should be needed. Leaving a + // comment pending a refactor. + // std::scoped_lock its_lock(the_logger_mutex__); + if (the_logger_ptr__ != nullptr) { + the_logger_ptr__->reset(); + delete the_logger_ptr__; + the_logger_ptr__ = nullptr; + } +} +#endif + +} // namespace logger +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/message.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/message.cpp new file mode 100644 index 00000000000..0ea45922fd8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/logger/src/message.cpp @@ -0,0 +1,209 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <ctime> +#include <fstream> +#include <iomanip> +#include <iostream> + +#ifdef ANDROID +#include <utils/Log.h> + +#ifdef ALOGE +#undef ALOGE +#endif + +#define ALOGE(LOG_TAG, ...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#ifndef LOGE +#define LOGE ALOGE +#endif + +#ifdef ALOGW +#undef ALOGW +#endif + +#define ALOGW(LOG_TAG, ...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) +#ifndef LOGW +#define LOGW ALOGW +#endif + +#ifdef ALOGI +#undef ALOGI +#endif + +#define ALOGI(LOG_TAG, ...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) +#ifndef LOGI +#define LOGI ALOGI +#endif + +#ifdef ALOGD +#undef ALOGD +#endif + +#define ALOGD(LOG_TAG, ...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) +#ifndef LOGD +#define LOGD ALOGD +#endif + +#ifdef ALOGV +#undef ALOGV +#endif + +#define ALOGV(LOG_TAG, ...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#ifndef LOGV +#define LOGV ALOGV +#endif + +#endif + +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/runtime.hpp> + +#include "../include/logger_impl.hpp" +#include "../../configuration/include/configuration.hpp" + +namespace vsomeip_v3 { +namespace logger { + +std::mutex message::mutex__; + +message::message(level_e _level) + : std::ostream(&buffer_), + level_(_level) { + + when_ = std::chrono::system_clock::now(); +} + +message::~message() try { + std::scoped_lock its_lock {mutex__}; + auto its_logger = logger_impl::get(); + + if (level_ > its_logger->get_loglevel()) + return; + + if (its_logger->has_console_log() || its_logger->has_file_log()) { + + // Prepare log level + const char *its_level; + switch (level_) { + case level_e::LL_FATAL: + its_level = "fatal"; + break; + case level_e::LL_ERROR: + its_level = "error"; + break; + case level_e::LL_WARNING: + its_level = "warning"; + break; + case level_e::LL_INFO: + its_level = "info"; + break; + case level_e::LL_DEBUG: + its_level = "debug"; + break; + case level_e::LL_VERBOSE: + its_level = "verbose"; + break; + default: + its_level = "none"; + }; + + // Prepare time stamp + auto its_time_t = std::chrono::system_clock::to_time_t(when_); + struct tm its_time; +#ifdef _WIN32 + localtime_s(&its_time, &its_time_t); +#else + localtime_r(&its_time_t, &its_time); +#endif + auto its_ms = (when_.time_since_epoch().count() / 100) % 1000000; + + if (its_logger->has_console_log()) { +#ifndef ANDROID + { + std::unique_lock<std::mutex> app_name_lock = its_logger->get_app_name_lock(); + std::cout << std::dec << std::setw(4) << its_time.tm_year + 1900 << "-" << std::dec + << std::setw(2) << std::setfill('0') << its_time.tm_mon + 1 << "-" + << std::dec << std::setw(2) << std::setfill('0') << its_time.tm_mday + << " " << std::dec << std::setw(2) << std::setfill('0') + << its_time.tm_hour << ":" << std::dec << std::setw(2) + << std::setfill('0') << its_time.tm_min << ":" << std::dec << std::setw(2) + << std::setfill('0') << its_time.tm_sec << "." << std::dec << std::setw(6) + << std::setfill('0') << its_ms << " " << its_logger->get_app_name() + << " [" << its_level << "] " << buffer_.data_.str() << std::endl; + } +#else + std::string app = runtime::get_property("LogApplication"); + + switch (level_) { + case level_e::LL_FATAL: + ALOGE(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + case level_e::LL_ERROR: + ALOGE(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + case level_e::LL_WARNING: + ALOGW(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + case level_e::LL_INFO: + ALOGI(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + case level_e::LL_DEBUG: + ALOGD(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + case level_e::LL_VERBOSE: + ALOGV(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + break; + default: + ALOGI(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str()); + }; +#endif // !ANDROID + } + + if (its_logger->has_file_log()) { + std::ofstream its_logfile(its_logger->get_logfile(), std::ios_base::app); + if (its_logfile.is_open()) { + its_logfile << std::dec << std::setw(4) << its_time.tm_year + 1900 << "-" + << std::dec << std::setw(2) << std::setfill('0') << its_time.tm_mon + 1 + << "-" << std::dec << std::setw(2) << std::setfill('0') + << its_time.tm_mday << " " << std::dec << std::setw(2) + << std::setfill('0') << its_time.tm_hour << ":" << std::dec + << std::setw(2) << std::setfill('0') << its_time.tm_min << ":" + << std::dec << std::setw(2) << std::setfill('0') << its_time.tm_sec + << "." << std::dec << std::setw(6) << std::setfill('0') << its_ms + << " [" << its_level << "] " << buffer_.data_.str() << std::endl; + } + } + } + if (its_logger->has_dlt_log()) { +#ifdef USE_DLT +#ifndef ANDROID + its_logger->log(level_, buffer_.data_.str().c_str()); +#endif +#endif // USE_DLT + } +} catch (const std::exception& e) { + std::cerr << "\nVSIP: Error destroying message class: " << e.what() << '\n'; + return; +} + +std::streambuf::int_type +message::buffer::overflow(std::streambuf::int_type c) { + if (c != EOF) { + data_ << (char)c; + } + + return c; +} + +std::streamsize +message::buffer::xsputn(const char *s, std::streamsize n) { + data_.write(s, n); + return n; +} + +} // namespace logger +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/deserializer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/deserializer.hpp new file mode 100644 index 00000000000..3ebb8231d01 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/deserializer.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_DESERIALIZER_HPP +#define VSOMEIP_V3_DESERIALIZER_HPP + +#include <vector> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +class message_impl; + +class deserializer { +public: + VSOMEIP_EXPORT deserializer(std::uint32_t _buffer_shrink_threshold); + VSOMEIP_EXPORT deserializer(byte_t *_data, std::size_t _length, + std::uint32_t _buffer_shrink_threshold); + VSOMEIP_EXPORT deserializer(const deserializer& _other); + VSOMEIP_EXPORT virtual ~deserializer(); + + VSOMEIP_EXPORT void set_data(const byte_t *_data, std::size_t _length); + VSOMEIP_EXPORT void set_data(const std::vector<byte_t> &_data); + VSOMEIP_EXPORT void append_data(const byte_t *_data, std::size_t _length); + VSOMEIP_EXPORT void drop_data(std::size_t _length); + + VSOMEIP_EXPORT std::size_t get_available() const; + VSOMEIP_EXPORT std::size_t get_remaining() const; + VSOMEIP_EXPORT void set_remaining(std::size_t _remaining); + + // to be used by applications to deserialize a message + VSOMEIP_EXPORT message_impl *deserialize_message(); + + // to be used (internally) by objects to deserialize their members + // Note: this needs to be encapsulated! + VSOMEIP_EXPORT bool deserialize(uint8_t& _value); + VSOMEIP_EXPORT bool deserialize(uint16_t& _value); + VSOMEIP_EXPORT bool deserialize(uint32_t& _value, + bool _omit_last_byte = false); + VSOMEIP_EXPORT bool deserialize(uint8_t *_data, std::size_t _length); + VSOMEIP_EXPORT bool deserialize(std::string& _target, std::size_t _length); + VSOMEIP_EXPORT bool deserialize(std::vector<uint8_t>& _value); + + VSOMEIP_EXPORT bool look_ahead(std::size_t _index, uint8_t &_value) const; + VSOMEIP_EXPORT bool look_ahead(std::size_t _index, uint16_t &_value) const; + VSOMEIP_EXPORT bool look_ahead(std::size_t _index, uint32_t &_value) const; + + VSOMEIP_EXPORT void reset(); + +#ifdef VSOMEIP_DEBUGGING + VSOMEIP_EXPORT void show() const; +#endif +protected: + std::vector<byte_t> data_; + std::vector<byte_t>::iterator position_; + std::size_t remaining_; +private: + const std::uint32_t buffer_shrink_threshold_; + std::uint32_t shrink_count_; + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_DESERIALIZER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_base_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_base_impl.hpp new file mode 100644 index 00000000000..2c953e98516 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_base_impl.hpp @@ -0,0 +1,71 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_MESSAGE_BASE_IMPL_HPP +#define VSOMEIP_V3_MESSAGE_BASE_IMPL_HPP + +#include <vsomeip/export.hpp> +#include <vsomeip/message.hpp> + +#include "message_header_impl.hpp" + +namespace vsomeip_v3 { + +class message_base_impl + : virtual public message_base { +public: + VSOMEIP_EXPORT message_base_impl(); + VSOMEIP_EXPORT virtual ~message_base_impl(); + + VSOMEIP_EXPORT message_t get_message() const; + VSOMEIP_EXPORT void set_message(message_t _message); + + VSOMEIP_EXPORT service_t get_service() const; + VSOMEIP_EXPORT void set_service(service_t _service); + + VSOMEIP_EXPORT instance_t get_instance() const; + VSOMEIP_EXPORT void set_instance(instance_t _instance); + + VSOMEIP_EXPORT method_t get_method() const; + VSOMEIP_EXPORT void set_method(method_t _method); + + VSOMEIP_EXPORT request_t get_request() const; + + VSOMEIP_EXPORT client_t get_client() const; + VSOMEIP_EXPORT void set_client(client_t _client); + + VSOMEIP_EXPORT session_t get_session() const; + VSOMEIP_EXPORT void set_session(session_t _session); + + VSOMEIP_EXPORT protocol_version_t get_protocol_version() const; + VSOMEIP_EXPORT void set_protocol_version(protocol_version_t _protocol_version); + + VSOMEIP_EXPORT interface_version_t get_interface_version() const; + VSOMEIP_EXPORT void set_interface_version(interface_version_t _interface_version); + + VSOMEIP_EXPORT message_type_e get_message_type() const; + VSOMEIP_EXPORT void set_message_type(message_type_e _type); + + VSOMEIP_EXPORT return_code_e get_return_code() const; + VSOMEIP_EXPORT void set_return_code(return_code_e _code); + + VSOMEIP_EXPORT bool is_reliable() const; + VSOMEIP_EXPORT void set_reliable(bool _is_reliable); + + VSOMEIP_EXPORT bool is_initial() const; + VSOMEIP_EXPORT void set_initial(bool _is_initial); + + VSOMEIP_EXPORT message * get_owner() const; + VSOMEIP_EXPORT void set_owner(message *_owner); + +protected: // members + message_header_impl header_; + bool is_reliable_; + bool is_initial_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_MESSAGE_BASE_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_header_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_header_impl.hpp new file mode 100644 index 00000000000..f82775fb23b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_header_impl.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_MESSAGE_HEADER_IMPL_HPP +#define VSOMEIP_V3_MESSAGE_HEADER_IMPL_HPP + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/internal/serializable.hpp> + +namespace vsomeip_v3 { + +class message_base; + +class message_header_impl: virtual public serializable { +public: + VSOMEIP_EXPORT message_header_impl(); + VSOMEIP_EXPORT message_header_impl(const message_header_impl& _header); + + VSOMEIP_EXPORT bool serialize(serializer *_to) const; + VSOMEIP_EXPORT bool deserialize(deserializer *_from); + + // internal + VSOMEIP_EXPORT message_base * get_owner() const; + VSOMEIP_EXPORT void set_owner(message_base *_owner); + +public: + service_t service_; + method_t method_; + length_t length_; + client_t client_; + session_t session_; + protocol_version_t protocol_version_; + interface_version_t interface_version_; + message_type_e type_; + return_code_e code_; + + instance_t instance_; + message_base *owner_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_MESSAGE_HEADER_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_impl.hpp new file mode 100644 index 00000000000..e04d4a7ebaf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/message_impl.hpp @@ -0,0 +1,68 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_MESSAGE_IMPL_HPP +#define VSOMEIP_V3_MESSAGE_IMPL_HPP + +#include <memory> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> +#include "message_base_impl.hpp" + +# if _MSC_VER >= 1300 +/* +* Diamond inheritance is used for the vsomeip::message_base base class. +* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class" +* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class +* by using a common abstract base class. This is also called cross delegation. +*/ +# pragma warning( disable : 4250 ) +# endif + +namespace vsomeip_v3 { + +class payload; + +class message_impl + : virtual public message, + virtual public message_base_impl { +public: + VSOMEIP_EXPORT message_impl(); + VSOMEIP_EXPORT virtual ~message_impl(); + + VSOMEIP_EXPORT length_t get_length() const; + VSOMEIP_EXPORT void set_length(length_t _length); + + VSOMEIP_EXPORT std::shared_ptr< payload > get_payload() const; + VSOMEIP_EXPORT void set_payload(std::shared_ptr< payload > _payload); + + VSOMEIP_EXPORT bool serialize(serializer *_to) const; + VSOMEIP_EXPORT bool deserialize(deserializer *_from); + + VSOMEIP_EXPORT uint8_t get_check_result() const; + VSOMEIP_EXPORT void set_check_result(uint8_t _check_result); + VSOMEIP_EXPORT bool is_valid_crc() const; + + VSOMEIP_EXPORT uid_t get_uid() const; + + VSOMEIP_EXPORT gid_t get_gid() const; + + VSOMEIP_EXPORT vsomeip_sec_client_t get_sec_client() const; + VSOMEIP_EXPORT void set_sec_client(const vsomeip_sec_client_t &_sec_client); + + VSOMEIP_EXPORT std::string get_env() const; + VSOMEIP_EXPORT void set_env(const std::string &_env); + +protected: // members + std::shared_ptr< payload > payload_; + uint8_t check_result_; + vsomeip_sec_client_t sec_client_; + std::string env_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_MESSAGE_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/payload_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/payload_impl.hpp new file mode 100644 index 00000000000..e63dbc39317 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/payload_impl.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PAYLOAD_IMPL_HPP +#define VSOMEIP_V3_PAYLOAD_IMPL_HPP + +#include <vsomeip/export.hpp> +#include <vsomeip/payload.hpp> + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +class serializer; +class deserializer; + +class payload_impl: public payload { +public: + VSOMEIP_EXPORT payload_impl(); + VSOMEIP_EXPORT payload_impl(const byte_t* _data, uint32_t _size); + VSOMEIP_EXPORT payload_impl(const std::vector<byte_t>& _data); + VSOMEIP_EXPORT payload_impl(const payload_impl& _payload); + VSOMEIP_EXPORT virtual ~payload_impl() = default; + + VSOMEIP_EXPORT bool operator== (const payload& _other); + + VSOMEIP_EXPORT byte_t* get_data(); + VSOMEIP_EXPORT const byte_t* get_data() const; + VSOMEIP_EXPORT length_t get_length() const; + + VSOMEIP_EXPORT void set_capacity(length_t _capacity); + + VSOMEIP_EXPORT void set_data(const byte_t* _data, length_t _length); + VSOMEIP_EXPORT void set_data(const std::vector<byte_t>& _data); + VSOMEIP_EXPORT void set_data(std::vector<byte_t>&& _data); + + VSOMEIP_EXPORT bool serialize(serializer* _to) const; + VSOMEIP_EXPORT bool deserialize(deserializer* _from); + +private: + std::vector<byte_t> data_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PAYLOAD_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/serializer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/serializer.hpp new file mode 100644 index 00000000000..bd626ab01f0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/include/serializer.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SERIALIZER_HPP +#define VSOMEIP_V3_SERIALIZER_HPP + +#include <vector> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +class serializable; + +class VSOMEIP_IMPORT_EXPORT serializer { +public: + serializer(std::uint32_t _buffer_shrink_threshold); + virtual ~serializer(); + + bool serialize(const serializable *_from); + + bool serialize(const uint8_t _value); + bool serialize(const uint16_t _value); + bool serialize(const uint32_t _value, bool _omit_last_byte = false); + bool serialize(const uint8_t *_data, uint32_t _length); + bool serialize(const std::vector<byte_t> &_data); + + virtual const uint8_t * get_data() const; + virtual uint32_t get_capacity() const; + virtual uint32_t get_size() const; + + virtual void set_data(uint8_t *_data, uint32_t _capacity); + + virtual void reset(); + +#ifdef VSOMEIP_DEBUGGING + virtual void show(); +#endif +private: +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + std::vector<byte_t> data_; + std::uint32_t shrink_count_; + std::uint32_t buffer_shrink_threshold_; +#ifdef _WIN32 +#pragma warning(pop) +#endif +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERIALIZER_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/deserializer.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/deserializer.cpp new file mode 100644 index 00000000000..746b83630d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/deserializer.cpp @@ -0,0 +1,247 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#ifdef VSOMEIP_DEBUGGING +#include <iomanip> +#include <sstream> +#endif +#include <vsomeip/internal/logger.hpp> + +#include "../include/message_impl.hpp" +#include "../include/deserializer.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +deserializer::deserializer(std::uint32_t _buffer_shrink_threshold) + : position_(data_.begin()), + remaining_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold), + shrink_count_(0) { +} + +deserializer::deserializer(byte_t *_data, std::size_t _length, + std::uint32_t _buffer_shrink_threshold) + : data_(_data, _data + _length), + position_(data_.begin()), + remaining_(_length), + buffer_shrink_threshold_(_buffer_shrink_threshold), + shrink_count_(0) { +} + +deserializer::deserializer(const deserializer &_other) + : data_(_other.data_), + position_(_other.position_), + remaining_(_other.remaining_), + buffer_shrink_threshold_(_other.buffer_shrink_threshold_), + shrink_count_(_other.shrink_count_) { +} + +deserializer::~deserializer() { +} + +std::size_t deserializer::get_available() const { + return data_.size(); +} + +std::size_t deserializer::get_remaining() const { + return remaining_; +} + +void deserializer::set_remaining(std::size_t _remaining) { + remaining_ = _remaining; +} + +bool deserializer::deserialize(uint8_t& _value) { + if (0 == remaining_) + return false; + + _value = *position_++; + + remaining_--; + return true; +} + +bool deserializer::deserialize(uint16_t& _value) { + if (2 > remaining_) + return false; + + uint8_t byte0, byte1; + byte0 = *position_++; + byte1 = *position_++; + remaining_ -= 2; + + uint8_t payload[2] = {byte0, byte1}; + _value = bithelper::read_uint16_be(payload); + + return true; +} + +bool deserializer::deserialize(uint32_t &_value, bool _omit_last_byte) { + if (3 > remaining_ || (!_omit_last_byte && 4 > remaining_)) + return false; + + uint8_t byte0 = 0, byte1, byte2, byte3; + if (!_omit_last_byte) { + byte0 = *position_++; + remaining_--; + } + byte1 = *position_++; + byte2 = *position_++; + byte3 = *position_++; + remaining_ -= 3; + + uint8_t payload[4] = {byte0, byte1, byte2, byte3}; + _value = bithelper::read_uint32_be(payload); + + return true; +} + +bool deserializer::deserialize(uint8_t *_data, std::size_t _length) { + if (_length > remaining_) + return false; + + std::memcpy(_data, &data_[static_cast<std::vector<byte_t>::size_type>(position_ - data_.begin())], _length); + position_ += static_cast<std::vector<byte_t>::difference_type>(_length); + remaining_ -= _length; + + return true; +} + +bool deserializer::deserialize(std::string &_target, std::size_t _length) { + if (_length > remaining_ || _length > _target.capacity()) { + return false; + } + _target.assign(position_, position_ + static_cast<std::vector<byte_t>::difference_type>(_length)); + position_ += static_cast<std::vector<byte_t>::difference_type>(_length); + remaining_ -= _length; + + return true; +} + +bool deserializer::deserialize(std::vector< uint8_t >& _value) { + if (_value.capacity() > remaining_) + return false; + + _value.assign(position_, position_ + + static_cast<std::vector<byte_t>::difference_type>(_value.capacity())); + position_ += static_cast<std::vector<byte_t>::difference_type>(_value.capacity()); + remaining_ -= _value.capacity(); + + return true; +} + +bool deserializer::look_ahead(std::size_t _index, uint8_t &_value) const { + if (_index > remaining_) + return false; + + _value = *(position_ + static_cast<std::vector<byte_t>::difference_type>(_index)); + + return true; +} + +bool deserializer::look_ahead(std::size_t _index, uint16_t &_value) const { + if (_index+1 > remaining_) + return false; + + std::vector< uint8_t >::iterator i = position_ + + static_cast<std::vector<byte_t>::difference_type>(_index); + _value = bithelper::read_uint16_be(&(*i)); + + return true; +} + +bool deserializer::look_ahead(std::size_t _index, uint32_t &_value) const { + if (_index+3 > remaining_) + return false; + + std::vector< uint8_t >::const_iterator i = position_ + static_cast<std::vector<byte_t>::difference_type>(_index); + _value = bithelper::read_uint32_be(&(*i)); + + return true; +} + +message_impl * deserializer::deserialize_message() try { + std::unique_ptr<message_impl> deserialized_message = std::make_unique<message_impl>(); + if (false == deserialized_message->deserialize(this)) { + VSOMEIP_ERROR << "SOME/IP message deserialization failed!"; + deserialized_message = nullptr; + } + + return deserialized_message.release(); +} +catch (const std::exception& e) { + VSOMEIP_ERROR << "SOME/IP message deserialization failed with exception: " << e.what(); + return nullptr; +} + +void deserializer::set_data(const byte_t *_data, std::size_t _length) { + if (0 != _data) { + data_.assign(_data, _data + _length); + position_ = data_.begin(); + remaining_ = static_cast<std::vector<byte_t>::size_type>(data_.end() - position_); + } else { + data_.clear(); + position_ = data_.end(); + remaining_ = 0; + } +} + +void +deserializer::set_data(const std::vector<byte_t> &_data) { + + data_ = std::move(_data); + position_ = data_.begin(); + remaining_ = data_.size(); +} + +void deserializer::append_data(const byte_t *_data, std::size_t _length) { + std::vector<byte_t>::difference_type offset = (position_ - data_.begin()); + data_.insert(data_.end(), _data, _data + _length); + position_ = data_.begin() + offset; + remaining_ += _length; +} + +void deserializer::drop_data(std::size_t _length) { + if (position_ + static_cast<std::vector<byte_t>::difference_type>(_length) < data_.end()) + position_ += static_cast<std::vector<byte_t>::difference_type>(_length); + else + position_ = data_.end(); +} + +void deserializer::reset() { + if (buffer_shrink_threshold_) { + if (data_.size() < (data_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + data_.clear(); + position_ = data_.begin(); + remaining_ = data_.size(); + if (buffer_shrink_threshold_ && shrink_count_ > buffer_shrink_threshold_) { + data_.shrink_to_fit(); + shrink_count_ = 0; + } +} + +#ifdef VSOMEIP_DEBUGGING +void deserializer::show() const { + std::stringstream its_message; + its_message << "(" + << std::hex << std::setw(2) << std::setfill('0') + << (int)*position_ << ", " + << std:: dec << remaining_ << ") " + << std::hex << std::setfill('0'); + for (int i = 0; i < data_.size(); ++i) + its_message << std::setw(2) << (int)data_[i] << " "; + VSOMEIP_INFO << its_message; +} +#endif + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_base_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_base_impl.cpp new file mode 100644 index 00000000000..c64a56f9287 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_base_impl.cpp @@ -0,0 +1,130 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/message_impl.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +message_base_impl::message_base_impl() + : is_reliable_(false), + is_initial_(false) { + header_.set_owner(this); +} + +message_base_impl::~message_base_impl() { +} + +// header interface +message_t message_base_impl::get_message() const { + const uint8_t header_message[] = {static_cast<uint8_t>((header_.service_ & 0xFF00) >> 8), + static_cast<uint8_t>( header_.service_ & 0x00FF), + static_cast<uint8_t>((header_.method_ & 0xFF00) >> 8), + static_cast<uint8_t>( header_.method_ & 0x00FF)}; + return bithelper::read_uint32_be(header_message); +} + +void message_base_impl::set_message(message_t _message) { + header_.service_ = bithelper::read_high_word(_message); + header_.method_ = bithelper::read_low_word(_message); +} + +service_t message_base_impl::get_service() const { + return header_.service_; +} + +void message_base_impl::set_service(service_t _service) { + header_.service_ = _service; +} + +instance_t message_base_impl::get_instance() const { + return header_.instance_; +} + +void message_base_impl::set_instance(instance_t _instance) { + header_.instance_ = _instance; +} + +method_t message_base_impl::get_method() const { + return header_.method_; +} + +void message_base_impl::set_method(method_t _method) { + header_.method_ = _method; +} + +request_t message_base_impl::get_request() const { + const uint8_t header_message[] = {static_cast<uint8_t>((header_.client_ & 0xFF00) >> 8), + static_cast<uint8_t>( header_.client_ & 0x00FF), + static_cast<uint8_t>((header_.session_ & 0xFF00) >> 8), + static_cast<uint8_t>( header_.session_ & 0x00FF)}; + return bithelper::read_uint32_be(header_message); +} + +client_t message_base_impl::get_client() const { + return header_.client_; +} + +void message_base_impl::set_client(client_t _client) { + header_.client_ = _client; +} + +session_t message_base_impl::get_session() const { + return header_.session_; +} + +void message_base_impl::set_session(session_t _session) { + header_.session_ = _session; +} + +protocol_version_t message_base_impl::get_protocol_version() const { + return header_.protocol_version_; +} + +void message_base_impl::set_protocol_version(protocol_version_t _protocol_version) { + header_.protocol_version_ = _protocol_version; +} + +interface_version_t message_base_impl::get_interface_version() const { + return header_.interface_version_; +} + +void message_base_impl::set_interface_version(interface_version_t _interface_version) { + header_.interface_version_ = _interface_version; +} + +message_type_e message_base_impl::get_message_type() const { + return header_.type_; +} + +void message_base_impl::set_message_type(message_type_e _type) { + header_.type_ = _type; +} + +return_code_e message_base_impl::get_return_code() const { + return header_.code_; +} + +void message_base_impl::set_return_code(return_code_e _code) { + header_.code_ = _code; +} + +bool message_base_impl::is_reliable() const { + return is_reliable_; +} + +void message_base_impl::set_reliable(bool _is_reliable) { + is_reliable_ = _is_reliable; +} + +bool message_base_impl::is_initial() const { + return is_initial_; +} + +void message_base_impl::set_initial(bool _is_initial) { + is_initial_ = _is_initial; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_header_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_header_impl.cpp new file mode 100644 index 00000000000..40b98c32a38 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_header_impl.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/defines.hpp> + +#include "../include/message_base_impl.hpp" +#include "../include/message_header_impl.hpp" +#include "../include/serializer.hpp" +#include "../include/deserializer.hpp" + +namespace vsomeip_v3 { + +message_header_impl::message_header_impl() + : service_(0x0), method_(0x0), length_(0x0), + client_(0x0), session_(0x0), + protocol_version_(0x1), interface_version_(0x0), + type_(message_type_e::MT_UNKNOWN), + code_(return_code_e::E_UNKNOWN), + instance_(0x0), owner_(0x0) { +} + +message_header_impl::message_header_impl(const message_header_impl &_header) + : service_(_header.service_), method_(_header.method_), + length_(_header.length_), + client_(_header.client_), session_(_header.session_), + protocol_version_(_header.protocol_version_), + interface_version_(_header.interface_version_), + type_(_header.type_), + code_(_header.code_), + instance_(_header.instance_), owner_(_header.owner_) { +} + +bool message_header_impl::serialize(serializer *_to) const { + return (0 != _to + && _to->serialize(service_) + && _to->serialize(method_) + && _to->serialize(owner_->get_length()) + && _to->serialize(client_) + && _to->serialize(session_) + && _to->serialize(protocol_version_) + && _to->serialize(interface_version_) + && _to->serialize(static_cast<uint8_t>(type_)) + && _to->serialize(static_cast<uint8_t>(code_))); +} + +bool message_header_impl::deserialize(deserializer *_from) { + bool is_successful; + + uint8_t tmp_message_type, tmp_return_code; + + is_successful = (0 != _from + && _from->deserialize(service_) + && _from->deserialize(method_) + && _from->deserialize(length_) + && _from->deserialize(client_) + && _from->deserialize(session_) + && _from->deserialize(protocol_version_) + && _from->deserialize(interface_version_) + && _from->deserialize(tmp_message_type) + && _from->deserialize(tmp_return_code)); + + if (is_successful) { + type_ = static_cast< message_type_e >(tmp_message_type); + code_ = static_cast< return_code_e >(tmp_return_code); + } + + return is_successful; +} + +message_base * message_header_impl::get_owner() const { + return owner_; +} + +void message_header_impl::set_owner(message_base *_owner) { + owner_ = _owner; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_impl.cpp new file mode 100644 index 00000000000..09db2972227 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/message_impl.cpp @@ -0,0 +1,96 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/defines.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> + +#include "../include/message_impl.hpp" +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif + +namespace vsomeip_v3 { + +message_impl::message_impl() + : payload_(runtime::get()->create_payload()), + check_result_ {0}, + sec_client_ {ANY_UID, ANY_GID, 0, VSOMEIP_SEC_PORT_UNUSED} { +} + +message_impl::~message_impl() { +} + +length_t message_impl::get_length() const { + return (VSOMEIP_SOMEIP_HEADER_SIZE + + (payload_ ? payload_->get_length() : 0)); +} + +std::shared_ptr< payload > message_impl::get_payload() const { + return payload_; +} + +void message_impl::set_payload(std::shared_ptr< payload > _payload) { + payload_ = _payload; +} + +bool message_impl::serialize(serializer *_to) const { + return (header_.serialize(_to) + && (payload_ ? payload_->serialize(_to) : true)); +} + +bool message_impl::deserialize(deserializer *_from) { + payload_ = runtime::get()->create_payload(); + bool is_successful = header_.deserialize(_from); + if (is_successful) { + payload_->set_capacity(header_.length_ - VSOMEIP_SOMEIP_HEADER_SIZE); + is_successful = payload_->deserialize(_from); + } + return is_successful; +} + +uint8_t message_impl::get_check_result() const { + return check_result_; +} + +void message_impl::set_check_result(uint8_t _check_result) { + check_result_ = _check_result; +} + +bool message_impl::is_valid_crc() const { + return (check_result_ == 0); +} + +uid_t message_impl::get_uid() const { + + return sec_client_.user; +} + +gid_t message_impl::get_gid() const { + + return sec_client_.group; +} + +vsomeip_sec_client_t message_impl::get_sec_client() const { + + return sec_client_; +} + +void message_impl::set_sec_client(const vsomeip_sec_client_t &_sec_client) { + + sec_client_ = _sec_client; +} + +std::string message_impl::get_env() const { + return env_; +} + +void message_impl::set_env(const std::string &_env) { + env_ = _env; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/payload_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/payload_impl.cpp new file mode 100644 index 00000000000..617fe67c225 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/payload_impl.cpp @@ -0,0 +1,74 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/deserializer.hpp" +#include "../include/payload_impl.hpp" +#include "../include/serializer.hpp" + +namespace vsomeip_v3 { + +payload_impl::payload_impl() + : data_() { +} + +payload_impl::payload_impl(const byte_t* _data, uint32_t _size) { + data_.assign(_data, _data + _size); +} + +payload_impl::payload_impl(const std::vector<byte_t>& _data) + : data_(_data) { +} + +payload_impl::payload_impl(const payload_impl& _payload) + : data_(_payload.data_) { +} + +bool payload_impl::operator==(const payload& _other) { + bool is_equal {get_length() == _other.get_length()}; + if (is_equal) { + is_equal = (0 == std::memcmp(get_data(), _other.get_data(), get_length())); + } + return is_equal; +} + +byte_t* payload_impl::get_data() { + return data_.data(); +} + +const byte_t* payload_impl::get_data() const { + return data_.data(); +} + +length_t payload_impl::get_length() const { + return length_t(data_.size()); +} + +void payload_impl::set_capacity(length_t _capacity) { + data_.reserve(_capacity); +} + +void payload_impl::set_data(const byte_t* _data, const length_t _length) { + data_.assign(_data, _data + _length); +} + +void payload_impl::set_data(const std::vector<byte_t>& _data) { + data_ = _data; +} + +void payload_impl::set_data(std::vector<byte_t>&& _data) { + data_ = std::move(_data); +} + +bool payload_impl::serialize(serializer* _to) const { + return (0 != _to && _to->serialize(data_)); +} + +bool payload_impl::deserialize(deserializer* _from) { + return (0 != _from && _from->deserialize(data_)); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/serializer.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/serializer.cpp new file mode 100644 index 00000000000..9f6f03427bf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/message/src/serializer.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//#include <cstring> + +#ifdef VSOMEIP_DEBUGGING +#include <iomanip> +#include <sstream> +#endif + +#include <vsomeip/internal/serializable.hpp> + +#include "../include/serializer.hpp" +#include "../../utility/include/bithelper.hpp" +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { + +serializer::serializer(std::uint32_t _buffer_shrink_threshold) : + data_(0), + shrink_count_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold) { +} + +serializer::~serializer() { +} + +bool serializer::serialize(const serializable *_from) { + return (_from && _from->serialize(this)); +} + +bool serializer::serialize(const uint8_t _value) { + data_.push_back(_value); + return true; +} + +bool serializer::serialize(const uint16_t _value) { + uint8_t nvalue[2] = {0}; + bithelper::write_uint16_le(_value, nvalue); + data_.push_back(nvalue[1]); + data_.push_back(nvalue[0]); + return true; +} + +bool serializer::serialize(const uint32_t _value, bool _omit_last_byte) { + uint8_t nvalue[4] = {0}; + bithelper::write_uint32_le(_value, nvalue); + + if (!_omit_last_byte) { + data_.push_back(nvalue[3]); + } + data_.push_back(nvalue[2]); + data_.push_back(nvalue[1]); + data_.push_back(nvalue[0]); + return true; +} + +bool serializer::serialize(const uint8_t *_data, uint32_t _length) { + try { + data_.insert(data_.end(), _data, _data + _length); + } catch(const std::bad_alloc &e) { + VSOMEIP_ERROR << "Couldn't allocate memory in serializer::serialize(*_data, length)" << e.what(); + return false; + } + return true; +} + +bool serializer::serialize(const std::vector<byte_t> &_data) { + try { + data_.insert(data_.end(),_data.begin(), _data.end()); + } catch(const std::bad_alloc &e) { + VSOMEIP_ERROR << "Couldn't allocate memory in serializer::serialize(vector)" << e.what(); + return false; + } + return true; +} + +const byte_t * serializer::get_data() const { + return data_.data(); +} + +uint32_t serializer::get_capacity() const { + return static_cast<std::uint32_t>(data_.max_size()); +} + +uint32_t serializer::get_size() const { + return static_cast<std::uint32_t>(data_.size()); +} + +void serializer::set_data(byte_t *_data, uint32_t _capacity) { + data_.clear(); + try { + data_.insert(data_.end(), _data, _data + _capacity); + } catch(const std::bad_alloc &e) { + VSOMEIP_ERROR << "Couldn't allocate memory in serializer::set_data" << e.what(); + } +} + +void serializer::reset() { + if (buffer_shrink_threshold_) { + if (data_.size() < (data_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + data_.clear(); + if (buffer_shrink_threshold_ && shrink_count_ > buffer_shrink_threshold_) { + data_.shrink_to_fit(); + shrink_count_ = 0; + } +} + +#ifdef VSOMEIP_DEBUGGING +void serializer::show() { + std::stringstream its_data; + its_data << "SERIALIZED: " + << std::setfill('0') << std::hex; + for (const byte_t& e : data_) + its_data << std::setw(2) << (int)e; + VSOMEIP_INFO << its_data.str(); +} +#endif + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/include/plugin_manager_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/include/plugin_manager_impl.hpp new file mode 100644 index 00000000000..9f755d60c63 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/include/plugin_manager_impl.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PLUGIN_MANAGER_IMPL_HPP +#define VSOMEIP_V3_PLUGIN_MANAGER_IMPL_HPP + +#include <vsomeip/internal/plugin_manager.hpp> + +#include <map> +#include <chrono> +#include <mutex> +#include <set> + +#include <vsomeip/constants.hpp> +#include <vsomeip/export.hpp> +#include <vsomeip/plugin.hpp> + +namespace vsomeip_v3 { + +class plugin_manager_impl : public plugin_manager { +public: + VSOMEIP_EXPORT static std::shared_ptr<plugin_manager_impl> get(); + + plugin_manager_impl(); + + ~plugin_manager_impl(); + + VSOMEIP_EXPORT void load_plugins(); + + VSOMEIP_EXPORT std::shared_ptr<plugin> get_plugin(plugin_type_e _type, + const std::string &_name); + + VSOMEIP_EXPORT std::shared_ptr<plugin> load_plugin( + const std::string& _library, plugin_type_e _type, + const uint32_t _version); + + VSOMEIP_EXPORT bool unload_plugin(plugin_type_e _type); + + VSOMEIP_EXPORT void * load_library(const std::string &_path); + VSOMEIP_EXPORT void * load_symbol(void * _handle, const std::string &_symbol); + VSOMEIP_EXPORT void unload_library(void * _handle); + +private: + void add_plugin(const std::shared_ptr<plugin> &_plugin, const std::string& _name); + + bool plugins_loaded_; + std::mutex loader_mutex_; + + std::map<plugin_type_e, std::map<std::string, std::shared_ptr<plugin> > > plugins_; + std::map<plugin_type_e, std::map<std::string, void*> > handles_; + std::recursive_mutex plugins_mutex_; + + static std::shared_ptr<plugin_manager_impl> the_plugin_manager__; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PLUGIN_MANAGER_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager.cpp new file mode 100644 index 00000000000..d64cbaaea2b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/plugin_manager_impl.hpp" + +namespace vsomeip_v3 { + +std::shared_ptr<plugin_manager> plugin_manager::get() { + return plugin_manager_impl::get(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager_impl.cpp new file mode 100644 index 00000000000..23b7b892af3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/plugin/src/plugin_manager_impl.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2016-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <sstream> +#include <vector> +#include <stdlib.h> +#include <iomanip> +#include <iostream> + +#ifdef _WIN32 + #ifndef _WINSOCKAPI_ + #include <Windows.h> + #endif +#else + #include <dlfcn.h> +#endif + +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/plugins/pre_configuration_plugin.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/plugin_manager_impl.hpp" + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +std::shared_ptr<plugin_manager_impl> plugin_manager_impl::the_plugin_manager__ = + std::make_shared<plugin_manager_impl>(); + +std::shared_ptr<plugin_manager_impl> plugin_manager_impl::get() { + return the_plugin_manager__; +} + +plugin_manager_impl::plugin_manager_impl() : + plugins_loaded_(false) { +} + +plugin_manager_impl::~plugin_manager_impl() { + handles_.clear(); + plugins_.clear(); +} + +void plugin_manager_impl::load_plugins() { + { + std::lock_guard<std::mutex> its_lock_start_stop(loader_mutex_); + if (plugins_loaded_) { + return; + } + plugins_loaded_ = true; + } + + // Get plug-ins libraries from environment + std::vector<std::string> plugins; + const char *its_plugins = getenv(VSOMEIP_ENV_LOAD_PLUGINS); + if (nullptr != its_plugins) { + std::string token; + std::stringstream ss(its_plugins); + while(std::getline(ss, token, ',')) { + plugins.push_back(token); + } + } + + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); + // Load plug-in info from libraries parsed before + for (const auto& plugin_name : plugins) { + void* handle = load_library(plugin_name); + plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>( + load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL)); + if (its_init_func) { + create_plugin_func its_create_func = (*its_init_func)(); + if (its_create_func) { + auto its_plugin = (*its_create_func)(); + if (its_plugin) { + handles_[its_plugin->get_plugin_type()][plugin_name] = handle; + switch (its_plugin->get_plugin_type()) { + case plugin_type_e::APPLICATION_PLUGIN: + if (its_plugin->get_plugin_version() + == VSOMEIP_APPLICATION_PLUGIN_VERSION) { + add_plugin(its_plugin, plugin_name); + } else { + VSOMEIP_ERROR << "Plugin version mismatch. " + << "Ignoring application plugin " + << its_plugin->get_plugin_name(); + } + break; + case plugin_type_e::PRE_CONFIGURATION_PLUGIN: + if (its_plugin->get_plugin_version() + == VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION) { + add_plugin(its_plugin, plugin_name); + } else { + VSOMEIP_ERROR << "Plugin version mismatch. Ignoring " + << "pre-configuration plugin " + << its_plugin->get_plugin_name(); + } + break; + default: + break; + } + } + } + } + } +} + +std::shared_ptr<plugin> plugin_manager_impl::get_plugin(plugin_type_e _type, + const std::string &_name) { + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); + auto its_type = plugins_.find(_type); + if (its_type != plugins_.end()) { + auto its_name = its_type->second.find(_name); + if (its_name != its_type->second.end()) { + return its_name->second; + } + } + return load_plugin(_name, _type, 1); +} + +std::shared_ptr<plugin> plugin_manager_impl::load_plugin(const std::string& _library, + plugin_type_e _type, uint32_t _version) { + void* handle = load_library(_library); + plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>( + load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL)); + if (its_init_func) { + create_plugin_func its_create_func = (*its_init_func)(); + if (its_create_func) { + handles_[_type][_library] = handle; + auto its_plugin = (*its_create_func)(); + if (its_plugin) { + if (its_plugin->get_plugin_type() == _type + && its_plugin->get_plugin_version() == _version) { + add_plugin(its_plugin, _library); + return its_plugin; + } else { + VSOMEIP_ERROR << "Plugin version mismatch. Ignoring plugin " + << its_plugin->get_plugin_name(); + } + } + } + } + return nullptr; +} + +bool plugin_manager_impl::unload_plugin(plugin_type_e _type) { + std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_); + const auto found_handle = handles_.find(_type); + if (found_handle != handles_.end()) { + for (const auto& its_name : found_handle->second) { +#ifdef _WIN32 + FreeLibrary((HMODULE)its_name.second); +#else + if (dlclose(its_name.second)) { + VSOMEIP_ERROR << "Unloading failed: (" << dlerror() << ")"; + } +#endif + } + } else { + VSOMEIP_ERROR << "plugin_manager_impl::unload_plugin didn't find plugin" + << " type:" << static_cast<int>(_type); + return false; + } + return plugins_.erase(_type); +} + +void plugin_manager_impl::add_plugin(const std::shared_ptr<plugin> &_plugin, const std::string& _name) { + plugins_[_plugin->get_plugin_type()][_name] = _plugin; +} + +void * plugin_manager_impl::load_library(const std::string &_path) { +#ifdef _WIN32 + return LoadLibrary(_path.c_str()); +#else + return dlopen(_path.c_str(), RTLD_LAZY | RTLD_LOCAL); +#endif +} + +void * plugin_manager_impl::load_symbol(void * _handle, const std::string &_symbol_name) { + void* symbol = nullptr; + if (_handle) { +#ifdef _WIN32 + symbol = GetProcAddress(reinterpret_cast<HMODULE>(_handle), _symbol_name.c_str()); +#else + symbol = dlsym(_handle, _symbol_name.c_str()); +#endif + + if (!symbol) { + char* error_message = nullptr; + +#ifdef _WIN32 + DWORD error_code = GetLastError(); + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + error_code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPSTR>(&error_message), + 0, + nullptr + ); +#else + error_message = dlerror(); +#endif + +#ifdef __QNX__ + VSOMEIP_ERROR << "Cannot load symbol " << std::quoted(_symbol_name.c_str()) << " because: " << error_message; +#else + VSOMEIP_ERROR << "Cannot load symbol " << std::quoted(_symbol_name) << " because: " << error_message; +#endif + +#ifdef _WIN32 + // Required to release memory allocated by FormatMessageA() + LocalFree(error_message); +#endif + } + } + return symbol; +} + +void plugin_manager_impl::unload_library(void * _handle) { + if (_handle) { +#ifdef _WIN32 + FreeLibrary(reinterpret_cast<HMODULE>(_handle)); +#else + dlclose(_handle); +#endif + } +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_ack_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_ack_command.hpp new file mode 100644 index 00000000000..ec112680c49 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_ack_command.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_ACK_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_ACK_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class assign_client_ack_command + : public command { +public: + assign_client_ack_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + client_t get_assigned() const; + void set_assigned(client_t _assigned); + +private: + client_t assigned_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_ACK_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_command.hpp new file mode 100644 index 00000000000..b1932da874f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/assign_client_command.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_COMMAND_HPP_ + +#include <string> + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class assign_client_command + : public command { +public: + assign_client_command(); + + // command + id_e get_id() const; + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + std::string get_name() const; + void set_name(const std::string &_name); + +private: + std::string name_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_ASSIGN_CLIENT_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/command.hpp new file mode 100644 index 00000000000..ccb8bdf2842 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/command.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2021-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_COMMAND_HPP_ + +#include <cstring> // memcpy +#include <vector> + +#include <vsomeip/primitive_types.hpp> + +#include "protocol.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +typedef uint32_t command_size_t; + +class command { +public: + inline id_e get_id() const { return id_; } + inline version_t get_version() const { return version_; } + inline client_t get_client() const { return client_; } + inline void set_client(client_t _client) { client_ = _client; } + inline command_size_t get_size() const { return size_; } + + virtual void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + virtual void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +protected: + id_e id_; + version_t version_; + client_t client_; + mutable command_size_t size_; + + command(id_e _id); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/config_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/config_command.hpp new file mode 100644 index 00000000000..c547f0abf1c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/config_command.hpp @@ -0,0 +1,67 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_CONFIG_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_CONFIG_COMMAND_HPP_ + +#include <map> + +#include "command.hpp" + +namespace vsomeip_v3::protocol { + +/** + * A command for sharing configurations between peers. + * + * It contains a list of arbitrary key-value pairs that represent additional + * information that is relevant to the peer, but is not covered by the other + * commands in the protocol. + * + * See the vsomeip protocol documentation for more information on how this command + * is structured. + */ +class config_command final : public command { +public: + /** Creates a new `config_command`. */ + config_command() : command(id_e::CONFIG_ID) { } + + /** + * Serializes the `config_command` into the given buffer. + * + * Serialized data will be represented in Little-Endian byte order. + */ + void serialize(std::vector<byte_t>& _buffer, error_e& _error) const override; + + /** + * Deserializes the `config_command` from the given buffer. + * + * Serialized data is expected to be in Little-Endian byte order. + */ + void deserialize(const std::vector<byte_t>& _buffer, error_e& _error) override; + + /** Inserts a configuration with the given value at the given key. */ + void insert(const std::string& _key, const std::string&& _value); + + /** Whether the map contains the given configuration. */ + bool contains(const std::string& _key) const; + + /** + * Returns the value of the given configuration. + * + * Panics if the key does not exist. + */ + const std::string& at(const std::string& _key) const; + + /** Returns a map of configurations and their associated values. */ + const std::map<std::string, std::string, std::less<>>& configs() const; + +private: + /** A map of configurations and their associated values. */ + std::map<std::string, std::string, std::less<>> configs_; +}; + +} // namespace vsomeip_v3::protocol + +#endif // VSOMEIP_V3_PROTOCOL_CONFIG_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/deregister_application_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/deregister_application_command.hpp new file mode 100644 index 00000000000..9b1bcb858b7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/deregister_application_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_DEREGISTER_APPLICATION_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_DEREGISTER_APPLICATION_COMMAND_HPP_ + +#include "simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class deregister_application_command + : public simple_command { + +public: + deregister_application_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_DEREGISTER_APPLICATION_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/distribute_security_policies_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/distribute_security_policies_command.hpp new file mode 100644 index 00000000000..2b2c6735dd3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/distribute_security_policies_command.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_DISTRIBUTE_SECURITY_POLICIES_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_DISTRIBUTE_SECURITY_POLICIES_COMMAND_HPP_ + +#include <map> +#include <memory> +#include <set> +#include <vector> + +#include "command.hpp" + +namespace vsomeip_v3 { + +class payload; +struct policy; + +namespace protocol { + +class distribute_security_policies_command + : public command { +public: + distribute_security_policies_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + std::set<std::shared_ptr<policy> > get_policies() const; + + void set_payloads(const std::map<uint32_t, std::shared_ptr<payload> > &_payloads); + +private: + std::set<std::shared_ptr<policy> > policies_; + std::vector<byte_t> payload_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_DISTRIBUTE_SECURITY_POLICIES_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/dummy_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/dummy_command.hpp new file mode 100644 index 00000000000..70f4f6c1b5d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/dummy_command.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_DUMMY_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_DUMMY_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class dummy_command + : public command { +public: + dummy_command(); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_DUMMY_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/expire_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/expire_command.hpp new file mode 100644 index 00000000000..3f9fdfa40d6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/expire_command.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_EXPIRE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_EXPIRE_COMMAND_HPP_ + +#include <memory> + +#include <vsomeip/structured_types.hpp> + +#include "subscribe_command_base.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { +namespace protocol { + +class expire_command + : public subscribe_command_base { + +public: + expire_command(); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_EXPIRE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/multiple_services_command_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/multiple_services_command_base.hpp new file mode 100644 index 00000000000..d679b166ed6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/multiple_services_command_base.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_MULTIPLE_SERVICES_COMMAND_BASE_HPP_ +#define VSOMEIP_V3_PROTOCOL_MULTIPLE_SERVICES_COMMAND_BASE_HPP_ + +#include <set> + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class multiple_services_command_base + : public command { +public: + multiple_services_command_base(id_e _id); + + // command + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + std::set<service> get_services() const; + void set_services(const std::set<service> &_services); + void add_service(const service &_service); + +private: + std::set<service> services_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_MULTIPLE_SERVICES_COMMAND_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offer_service_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offer_service_command.hpp new file mode 100644 index 00000000000..22e5f36ac5d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offer_service_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_OFFER_SERVICE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_OFFER_SERVICE_COMMAND_HPP_ + +#include "service_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class offer_service_command + : public service_command_base { + +public: + offer_service_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_OFFER_SERVICE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_request_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_request_command.hpp new file mode 100644 index 00000000000..3ced949856b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_request_command.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_REQUEST_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_REQUEST_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class offered_services_request_command + : public command { + +public: + offered_services_request_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + offer_type_e get_offer_type() const; + void set_offer_type(offer_type_e _offer_type); + +private: + offer_type_e offer_type_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_REQUEST_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_response_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_response_command.hpp new file mode 100644 index 00000000000..79a8f2c96a1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/offered_services_response_command.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_RESPONSE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_RESPONSE_COMMAND_HPP_ + +#include "multiple_services_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class offered_services_response_command + : public multiple_services_command_base { +public: + offered_services_response_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_OFFERED_SERVICES_RESPONSE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/ping_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/ping_command.hpp new file mode 100644 index 00000000000..369e2551aae --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/ping_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_PING_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_PING_COMMAND_HPP_ + +#include "simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class ping_command + : public simple_command { + +public: + ping_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_PING_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/pong_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/pong_command.hpp new file mode 100644 index 00000000000..1876f0d45d4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/pong_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_PONG_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_PONG_COMMAND_HPP_ + +#include "simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class pong_command + : public simple_command { + +public: + pong_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_PONG_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/protocol.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/protocol.hpp new file mode 100644 index 00000000000..c33195904b4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/protocol.hpp @@ -0,0 +1,143 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_PROTOCOL_HPP_ +#define VSOMEIP_V3_PROTOCOL_PROTOCOL_HPP_ + +#include <vsomeip/constants.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace protocol { + +typedef uint16_t version_t; +typedef uint32_t command_size_t; + +enum class id_e : uint8_t { + ASSIGN_CLIENT_ID = 0x00, + ASSIGN_CLIENT_ACK_ID = 0x01, + REGISTER_APPLICATION_ID = 0x02, + DEREGISTER_APPLICATION_ID = 0x03, + // APPLICATION_LOST_ID = 0x04, + ROUTING_INFO_ID = 0x05, + REGISTERED_ACK_ID = 0x06, + PING_ID = 0x07, + PONG_ID = 0x08, + OFFER_SERVICE_ID = 0x10, + STOP_OFFER_SERVICE_ID = 0x11, + SUBSCRIBE_ID = 0x12, + UNSUBSCRIBE_ID = 0x13, + REQUEST_SERVICE_ID = 0x14, + RELEASE_SERVICE_ID = 0x15, + SUBSCRIBE_NACK_ID = 0x16, + SUBSCRIBE_ACK_ID = 0x17, + SEND_ID = 0x18, + NOTIFY_ID = 0x19, + NOTIFY_ONE_ID = 0x1A, + REGISTER_EVENT_ID = 0x1B, + UNREGISTER_EVENT_ID = 0x1C, + ID_RESPONSE_ID = 0x1D, + ID_REQUEST_ID = 0x1E, + OFFERED_SERVICES_REQUEST_ID = 0x1F, + OFFERED_SERVICES_RESPONSE_ID = 0x20, + UNSUBSCRIBE_ACK_ID = 0x21, + RESEND_PROVIDED_EVENTS_ID = 0x22, + UPDATE_SECURITY_POLICY_ID = 0x23, + UPDATE_SECURITY_POLICY_RESPONSE_ID = 0x24, + REMOVE_SECURITY_POLICY_ID = 0x25, + REMOVE_SECURITY_POLICY_RESPONSE_ID = 0x26, + UPDATE_SECURITY_CREDENTIALS_ID = 0x27, + DISTRIBUTE_SECURITY_POLICIES_ID = 0x28, + UPDATE_SECURITY_POLICY_INT_ID = 0x29, + EXPIRE_ID = 0x2A, + SUSPEND_ID = 0x30, + CONFIG_ID = 0x31, + UNKNOWN_ID = 0xFF +}; + +enum class error_e : uint8_t { + ERROR_OK = 0x00, + ERROR_NOT_ENOUGH_BYTES = 0x01, + ERROR_MAX_COMMAND_SIZE_EXCEEDED = 0x02, + ERROR_MISMATCH = 0x04, + ERROR_MALFORMED = 0x08, + ERROR_NOT_ALLOWED = 0x10, + ERROR_UNKNOWN = 0xff +}; + +enum class routing_info_entry_type_e : std::uint8_t { + RIE_ADD_CLIENT = 0x00, + RIE_DELETE_CLIENT = 0x01, + RIE_ADD_SERVICE_INSTANCE = 0x02, + RIE_DELETE_SERVICE_INSTANCE = 0x04, + RIE_UNKNOWN = 0xff +}; + +typedef uint16_t pending_id_t; + +struct service { + service_t service_; + instance_t instance_; + major_version_t major_; + minor_version_t minor_; + + service() + : service_(ANY_SERVICE), + instance_(ANY_INSTANCE), + major_(ANY_MAJOR), + minor_(ANY_MINOR) { + } + + service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) + : service_(_service), + instance_(_instance), + major_(_major), + minor_(_minor) { + } + + bool operator<(const service &_other) const { + + return (service_ < _other.service_ + || (service_ == _other.service_ + && instance_ < _other.instance_)); + } +}; + +static const version_t MAX_SUPPORTED_VERSION = 0; + +static const size_t TAG_SIZE = 4; +static const size_t COMMAND_HEADER_SIZE = 9; +static const size_t SEND_COMMAND_HEADER_SIZE = 15; +static const size_t ROUTING_INFO_ENTRY_HEADER_SIZE = 7; + +static const size_t COMMAND_POSITION_ID = 0; +static const size_t COMMAND_POSITION_VERSION = 1; +static const size_t COMMAND_POSITION_CLIENT = 3; +static const size_t COMMAND_POSITION_SIZE = 5; +static const size_t COMMAND_POSITION_PAYLOAD = 9; + +static inline id_e get_command(byte_t _byte) { + + id_e its_id(id_e::UNKNOWN_ID); + if (_byte <= static_cast<byte_t>(id_e::SUSPEND_ID)) + its_id = static_cast<id_e>(_byte); + return its_id; +} + +static inline bool operator==(const byte_t &_lhs, const id_e &_rhs) { + + return (_lhs == static_cast<byte_t>(_rhs)); +} + +static inline bool operator==(const id_e &_lhs, const byte_t &_rhs) { + + return (_rhs == _lhs); +} + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_PROTOCOL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_application_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_application_command.hpp new file mode 100644 index 00000000000..ffb15ad8741 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_application_command.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REGISTER_APPLICATION_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REGISTER_APPLICATION_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class register_application_command + : public command { + +public: + register_application_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + port_t get_port() const; + void set_port(port_t _port); + +private: + port_t port_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REGISTER_APPLICATION_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_event.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_event.hpp new file mode 100644 index 00000000000..9793b9f3f60 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_event.hpp @@ -0,0 +1,67 @@ +#ifndef VSOMEIP_V3_PROTOCOL_REGISTER_EVENT_HPP_ +#define VSOMEIP_V3_PROTOCOL_REGISTER_EVENT_HPP_ + +#include <set> +#include <vector> +#include <vsomeip/constants.hpp> +#include <cstring> + +#include "protocol.hpp" +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace protocol { + +class register_event { +public: + register_event(service_t service = ANY_SERVICE, instance_t instance = ANY_INSTANCE, + event_t event = ANY_EVENT, event_type_e event_type = event_type_e::ET_UNKNOWN, + bool is_provided = false, reliability_type_e reliability = reliability_type_e::RT_UNKNOWN, + bool is_cyclic = false, uint16_t num_eventg = 0, + const std::set<eventgroup_t> &eventgroups = std::set<eventgroup_t>()); + void serialize(std::vector<byte_t> &_buffer, size_t &_offset, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, size_t &_offset, error_e &_error); + + service_t get_service() const { return service_; } + void set_service(service_t _service) { service_ = _service; } + + instance_t get_instance() const { return instance_; } + void set_instance(instance_t _instance) { instance_ = _instance; } + + event_t get_event() const { return event_; } + void set_event(event_t _event) { event_ = _event; } + + event_type_e get_event_type() const { return event_type_; } + void set_event_type(event_type_e _event_type) { event_type_ = _event_type; } + + bool is_provided() const { return is_provided_; } + void set_provided(bool _is_provided) { is_provided_ = _is_provided; } + + reliability_type_e get_reliability() const { return reliability_; } + void set_reliability(reliability_type_e _reliability) { reliability_ = _reliability; } + + bool is_cyclic() const { return is_cyclic_; } + void set_cyclic(bool _cyclic) { is_cyclic_ = _cyclic; } + + uint16_t get_num_eventgroups() const { return num_eventg_; } + + std::set<eventgroup_t> get_eventgroups() const { return eventgroups_; } + void set_eventgroups(const std::set<eventgroup_t> &_eventgroups); + +private: + service_t service_; + instance_t instance_; + event_t event_; + event_type_e event_type_; + bool is_provided_; + reliability_type_e reliability_; + bool is_cyclic_; + uint16_t num_eventg_; + std::set<eventgroup_t> eventgroups_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REGISTER_EVENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_events_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_events_command.hpp new file mode 100644 index 00000000000..23dd7faea9d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/register_events_command.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REGISTER_EVENTS_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REGISTER_EVENTS_COMMAND_HPP_ + +#include <set> + +#include <vsomeip/enumeration_types.hpp> + +#include "command.hpp" +#include "register_event.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class register_events_command + : public command { +public: + + register_events_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + std::size_t get_num_registrations() const; + + bool add_registration(const register_event &_register_event); + bool get_registration_at(std::size_t _position, register_event & _reg) const; + +private: + std::vector<register_event> registrations_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REGISTER_EVENTS_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/registered_ack_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/registered_ack_command.hpp new file mode 100644 index 00000000000..0ae85ba9eb4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/registered_ack_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REGISTERED_ACK_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REGISTERED_ACK_COMMAND_HPP_ + +#include "simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class registered_ack_command + : public simple_command { + +public: + registered_ack_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REGISTERED_ACK_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/release_service_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/release_service_command.hpp new file mode 100644 index 00000000000..537fd14aa12 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/release_service_command.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_RELEASE_SERVICE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_RELEASE_SERVICE_COMMAND_HPP_ + +#include <set> + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class release_service_command + : public command { +public: + release_service_command(); + + // command + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + +private: + service service_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_RELEASE_SERVICE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_command.hpp new file mode 100644 index 00000000000..83480e45a9c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_command.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class remove_security_policy_command + : public command { +public: + remove_security_policy_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + uint32_t get_update_id() const; + void set_update_id(uint32_t _update_id); + + uid_t get_uid() const; + void set_uid(uid_t _uid); + + gid_t get_gid() const; + void set_gid(gid_t _gid); + +private: + uint32_t update_id_; + uid_t uid_; + gid_t gid_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_response_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_response_command.hpp new file mode 100644 index 00000000000..7deda2cbbc9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/remove_security_policy_response_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ + +#include "security_policy_response_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class remove_security_policy_response_command + : public security_policy_response_command_base { + +public: + remove_security_policy_response_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REMOVE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/request_service_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/request_service_command.hpp new file mode 100644 index 00000000000..945247eacbc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/request_service_command.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_REQUEST_SERVICE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_REQUEST_SERVICE_COMMAND_HPP_ + +#include "multiple_services_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class request_service_command + : public multiple_services_command_base { +public: + request_service_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REQUEST_SERVICE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/resend_provided_events_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/resend_provided_events_command.hpp new file mode 100644 index 00000000000..1fc493c0961 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/resend_provided_events_command.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_RESEND_PROVIDED_EVENTS_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_RESEND_PROVIDED_EVENTS_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class resend_provided_events_command + : public command { +public: + resend_provided_events_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + pending_remote_offer_id_t get_remote_offer_id() const; + void set_remote_offer_id(pending_remote_offer_id_t _remote_offer_id); + +private: + pending_remote_offer_id_t remote_offer_id_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_RESEND_PROVIDED_EVENTS_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_command.hpp new file mode 100644 index 00000000000..2cb0ab74593 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_command.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_ROUTING_INFO_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_ROUTING_INFO_COMMAND_HPP_ + +#include "command.hpp" +#include "routing_info_entry.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class routing_info_command + : public command { +public: + routing_info_command(); + + // command + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + const std::vector<routing_info_entry> &get_entries() const; + void set_entries(std::vector<routing_info_entry> &&_entries); + void add_entry(const routing_info_entry &_entry); + +private: + std::vector<routing_info_entry> entries_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_ROUTING_INFO_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_entry.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_entry.hpp new file mode 100644 index 00000000000..b27190b1485 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/routing_info_entry.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_ROUTING_INFO_ENTRY_HPP_ +#define VSOMEIP_V3_PROTOCOL_ROUTING_INFO_ENTRY_HPP_ + +#include <vector> + +#include <boost/asio/ip/address.hpp> + +#include "protocol.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class routing_info_entry { +public: + routing_info_entry(); + routing_info_entry(const routing_info_entry &_source); + + void serialize(std::vector<byte_t> &_buffer, size_t &_index, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, size_t &_index, + error_e &_error); + + routing_info_entry_type_e get_type() const; + void set_type(routing_info_entry_type_e _type); + + size_t get_size() const; + + client_t get_client() const; + void set_client(client_t _client); + + boost::asio::ip::address get_address() const; + void set_address(const boost::asio::ip::address &_address); + + port_t get_port() const; + void set_port(port_t _port); + + const std::vector<service> &get_services() const; + void add_service(const service &_service); + +private: + routing_info_entry_type_e type_; + + client_t client_; + + boost::asio::ip::address address_; + port_t port_; + + std::vector<service> services_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_ROUTING_INFO_ENTRY_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/security_policy_response_command_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/security_policy_response_command_base.hpp new file mode 100644 index 00000000000..2bb4ba6d0a2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/security_policy_response_command_base.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SECURITY_POLICY_RESPONSE_COMMAND_BASE_HPP_ +#define VSOMEIP_V3_PROTOCOL_SECURITY_POLICY_RESPONSE_COMMAND_BASE_HPP_ + +#include <memory> + +#include "command.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +struct policy; + +namespace protocol { + +class security_policy_response_command_base + : public command { +public: + security_policy_response_command_base(id_e _id); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + uint32_t get_update_id() const; + void set_update_id(uint32_t _update_id); + +private: + uint32_t update_id_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SECURITY_POLICY_RESPONSE_COMMAND_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/send_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/send_command.hpp new file mode 100644 index 00000000000..cb10b450f74 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/send_command.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SEND_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SEND_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class send_command + : public command { +public: + send_command(id_e _id); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + bool is_reliable() const; + void set_reliable(bool _is_reliable); + + uint8_t get_status() const; + void set_status(uint8_t _status); + + client_t get_target() const; + void set_target(client_t _target); + + // TODO: Optimize this as the vector might be huge! + std::vector<byte_t> get_message() const; + void set_message(const std::vector<byte_t> &_message); + +private: + + instance_t instance_; + bool is_reliable_; + uint8_t status_; // TODO: DO WE REALLY NEED THIS? + client_t target_; + std::vector<byte_t> message_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_BASIC_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/service_command_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/service_command_base.hpp new file mode 100644 index 00000000000..05b488d772b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/service_command_base.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SERVICE_COMMAND_BASE_HPP_ +#define VSOMEIP_V3_PROTOCOL_SERVICE_COMMAND_BASE_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class service_command_base + : public command { + +public: + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + major_version_t get_major() const; + void set_major(major_version_t _major); + + minor_version_t get_minor() const; + void set_minor(minor_version_t _minor); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +protected: + service_command_base(id_e _id); + +private: + service service_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SERVICE_COMMAND_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/simple_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/simple_command.hpp new file mode 100644 index 00000000000..09ae8fd70e6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/simple_command.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SIMPLE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SIMPLE_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class simple_command + : public command { +public: + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +protected: + simple_command(id_e _id); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SIMPLE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/stop_offer_service_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/stop_offer_service_command.hpp new file mode 100644 index 00000000000..a9a51d29666 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/stop_offer_service_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_STOP_OFFER_SERVICE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_STOP_OFFER_SERVICE_COMMAND_HPP_ + +#include "service_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class stop_offer_service_command + : public service_command_base { + +public: + stop_offer_service_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_STOP_OFFER_SERVICE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command.hpp new file mode 100644 index 00000000000..b3f4c762a2f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_HPP_ + +#include "subscribe_ack_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class subscribe_ack_command + : public subscribe_ack_command_base { + +public: + subscribe_ack_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command_base.hpp new file mode 100644 index 00000000000..3a738b9a113 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_ack_command_base.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_BASE_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_BASE_HPP_ + +#include <memory> + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class subscribe_ack_command_base + : public command { + +public: + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + eventgroup_t get_eventgroup() const; + void set_eventgroup(eventgroup_t _eventgroup); + + client_t get_subscriber() const; + void set_subscriber(client_t _subscriber); + + event_t get_event() const; + void set_event(event_t _event); + + pending_id_t get_pending_id() const; + void set_pending_id(pending_id_t _pending_id); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +protected: + subscribe_ack_command_base(id_e _id); + + service_t service_; + instance_t instance_; + eventgroup_t eventgroup_; + client_t subscriber_; + event_t event_; + pending_id_t pending_id_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUBSCRIBE_ACK_COMMAND_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command.hpp new file mode 100644 index 00000000000..5453f72c2da --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_HPP_ + +#include <memory> + +#include "subscribe_command_base.hpp" + +namespace vsomeip_v3 { + +struct debounce_filter_impl_t; + +namespace protocol { + +class subscribe_command + : public subscribe_command_base { + +public: + subscribe_command(); + + std::shared_ptr<debounce_filter_impl_t> get_filter() const; + void set_filter(const std::shared_ptr<debounce_filter_impl_t> &_filter); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +private: + std::shared_ptr<debounce_filter_impl_t> filter_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command_base.hpp new file mode 100644 index 00000000000..a16c2fe19c1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_command_base.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_BASE_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_BASE_HPP_ + +#include <memory> + +#include <vsomeip/structured_types.hpp> + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class subscribe_command_base + : public command { + +public: + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + eventgroup_t get_eventgroup() const; + void set_eventgroup(eventgroup_t _eventgroup); + + major_version_t get_major() const; + void set_major(major_version_t _major); + + event_t get_event() const; + void set_event(event_t _event); + + pending_id_t get_pending_id() const; + void set_pending_id(pending_id_t _pending_id); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +protected: + subscribe_command_base(id_e _id); + + service_t service_; + instance_t instance_; + eventgroup_t eventgroup_; + major_version_t major_; + event_t event_; + pending_id_t pending_id_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUBSCRIBE_COMMAND_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_nack_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_nack_command.hpp new file mode 100644 index 00000000000..5b79ce51941 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/subscribe_nack_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUBSCRIBE_NACK_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUBSCRIBE_NACK_COMMAND_HPP_ + +#include "subscribe_ack_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class subscribe_nack_command + : public subscribe_ack_command_base { + +public: + subscribe_nack_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUBSCRIBE_NACK_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/suspend_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/suspend_command.hpp new file mode 100644 index 00000000000..414b36f146a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/suspend_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_SUSPEND_HPP_ +#define VSOMEIP_V3_PROTOCOL_SUSPEND_HPP_ + +#include "simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class suspend_command + : public simple_command { + +public: + suspend_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_SUSPEND_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unregister_event_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unregister_event_command.hpp new file mode 100644 index 00000000000..287eac799d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unregister_event_command.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UNREGISTER_EVENT_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UNREGISTER_EVENT_COMMAND_HPP_ + +#include <set> + +#include <vsomeip/enumeration_types.hpp> + +#include "command.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { +namespace protocol { + +class unregister_event_command + : public command { +public: + unregister_event_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + event_t get_event() const; + void set_event(event_t _event); + + bool is_provided() const; + void set_provided(bool _is_provided); + +private: + service_t service_; + instance_t instance_; + event_t event_; + bool is_provided_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_REGISTER_EVENT_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_ack_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_ack_command.hpp new file mode 100644 index 00000000000..7afaa1d5e63 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_ack_command.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_ACK_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_ACK_COMMAND_HPP_ + +#include "command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class unsubscribe_ack_command + : public command { + +public: + unsubscribe_ack_command(); + + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + eventgroup_t get_eventgroup() const; + void set_eventgroup(eventgroup_t _eventgroup); + + pending_id_t get_pending_id() const; + void set_pending_id(pending_id_t _pending_id); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); + +private: + service_t service_; + instance_t instance_; + eventgroup_t eventgroup_; + pending_id_t pending_id_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_ACK_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_command.hpp new file mode 100644 index 00000000000..e0a05ce36c0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/unsubscribe_command.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_COMMAND_HPP_ + +#include <memory> + +#include <vsomeip/structured_types.hpp> + +#include "subscribe_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class unsubscribe_command + : public subscribe_command_base { + +public: + unsubscribe_command(); + + void serialize(std::vector<byte_t> &_buffer, + error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, + error_e &_error); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_UNSUBSCRIBE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_credentials_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_credentials_command.hpp new file mode 100644 index 00000000000..37d9c34fc3e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_credentials_command.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_CREDENTIALS_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_CREDENTIALS_COMMAND_HPP_ + +#include <set> + +#include "command.hpp" + +namespace vsomeip_v3 { + +struct policy; + +namespace protocol { + +class update_security_credentials_command + : public command { +public: + update_security_credentials_command(); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + std::set<std::pair<uid_t, gid_t> > get_credentials() const; + void set_credentials( + const std::set<std::pair<uid_t, gid_t> > &_credentials); + +private: + std::set<std::pair<uid_t, gid_t> > credentials_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_CREDENTIALS_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_command.hpp new file mode 100644 index 00000000000..9a42d649da2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_command.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_COMMAND_HPP_ + +#include <memory> + +#include "command.hpp" + +namespace vsomeip_v3 { + +struct policy; + +namespace protocol { + +class update_security_policy_command + : public command { +public: + update_security_policy_command(bool _is_internal = false); + + void serialize(std::vector<byte_t> &_buffer, error_e &_error) const; + void deserialize(const std::vector<byte_t> &_buffer, error_e &_error); + + // specific + uint32_t get_update_id() const; + void set_update_id(uint32_t _update_id); + + std::shared_ptr<policy> get_policy() const; + void set_policy(const std::shared_ptr<policy> &_policy); + +private: + uint32_t update_id_; + std::shared_ptr<policy> policy_; +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_response_command.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_response_command.hpp new file mode 100644 index 00000000000..002b00127a3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/include/update_security_policy_response_command.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ +#define VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ + +#include "security_policy_response_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +class update_security_policy_response_command + : public security_policy_response_command_base { + +public: + update_security_policy_response_command(); +}; + +} // namespace protocol +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PROTOCOL_UPDATE_SECURITY_POLICY_RESPONSE_COMMAND_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_ack_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_ack_command.cpp new file mode 100644 index 00000000000..82c3be50078 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_ack_command.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/assign_client_ack_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +assign_client_ack_command::assign_client_ack_command() + : command(id_e::ASSIGN_CLIENT_ACK_ID) { + +} + +void +assign_client_ack_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(assigned_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(sizeof(assigned_)); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + std::memcpy(&_buffer[COMMAND_POSITION_PAYLOAD], &assigned_, + sizeof(assigned_)); +} + +void +assign_client_ack_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(assigned_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&assigned_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(assigned_)); +} + +client_t +assign_client_ack_command::get_assigned() const { + + return assigned_; +} + +void +assign_client_ack_command::set_assigned(client_t _assigned) { + + assigned_ = _assigned; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_command.cpp new file mode 100644 index 00000000000..c5ebdfb59c6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/assign_client_command.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/internal/logger.hpp> +#include "../include/assign_client_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +assign_client_command::assign_client_command() + : command(id_e::ASSIGN_CLIENT_ID) { + +} + +void +assign_client_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + name_.length()); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(name_.length()); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + if (!name_.empty()) + std::memcpy(&_buffer[COMMAND_POSITION_PAYLOAD], name_.data(), name_.length()); +} + +void +assign_client_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (_buffer.size() < COMMAND_HEADER_SIZE) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // name? + if (size_ > 0) + name_.assign(&_buffer[COMMAND_POSITION_PAYLOAD], + &_buffer[_buffer.size()-1]); +} + +std::string +assign_client_command::get_name() const { + + return name_; +} + +void +assign_client_command::set_name(const std::string &_name) { + + name_ = _name; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/command.cpp new file mode 100644 index 00000000000..fe338b06ab6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/command.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +command::command(id_e _id) + : id_(_id), + version_(MAX_SUPPORTED_VERSION), + client_(0), + size_(0) { +} + +void +command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + // buffer space reservation is done within the code of + // the derived classes that call this method + + _buffer[0] = static_cast<byte_t>(id_); + std::memcpy(&_buffer[COMMAND_POSITION_VERSION], &version_, + sizeof(version_)); + std::memcpy(&_buffer[COMMAND_POSITION_CLIENT], &client_, + sizeof(client_)); + std::memcpy(&_buffer[COMMAND_POSITION_SIZE], &size_, + sizeof(size_)); + + _error = error_e::ERROR_OK; +} + +void +command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + // buffer size check (size >= header size) is + // done within the code of the derived classes + // that call this method + + // If the id_ is set to "UNKNOWN", read it. + // Otherwise check it. + if (id_ == id_e::UNKNOWN_ID) { + + id_ = static_cast<id_e>(_buffer[0]); + } else if (_buffer[0] != static_cast<byte_t>(id_)) { + + _error = error_e::ERROR_MISMATCH; + return; + } + + std::memcpy(&version_, &_buffer[COMMAND_POSITION_VERSION], + sizeof(version_)); + std::memcpy(&client_, &_buffer[COMMAND_POSITION_CLIENT], + sizeof(client_)); + std::memcpy(&size_, &_buffer[COMMAND_POSITION_SIZE], + sizeof(size_)); + + _error = error_e::ERROR_OK; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/config_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/config_command.cpp new file mode 100644 index 00000000000..619aede98fd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/config_command.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/config_command.hpp" + +#include <functional> +#include <limits> + +namespace vsomeip_v3::protocol { + +void config_command::serialize(std::vector<byte_t>& _buffer, error_e& _error) const { + size_t size = COMMAND_HEADER_SIZE; + for (const auto& [key, value] : configs_) { + size += sizeof(std::uint32_t) * 2; + size += key.size(); + size += value.size(); + } + if (size > std::numeric_limits<command_size_t>::max()) { + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + _buffer.resize(size); + size_ = static_cast<command_size_t>(size - COMMAND_HEADER_SIZE); + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) { + return; + } + + size_t write_position(COMMAND_POSITION_PAYLOAD); + for (const auto& [key, value] : configs_) { + auto key_size = static_cast<std::uint32_t>(key.size()); + std::memcpy(&_buffer[write_position], &key_size, sizeof(std::uint32_t)); + write_position += sizeof(std::uint32_t); + + std::memcpy(&_buffer[write_position], key.data(), key.length()); + write_position += key_size; + + auto value_size = static_cast<std::uint32_t>(value.size()); + std::memcpy(&_buffer[write_position], &value_size, sizeof(std::uint32_t)); + write_position += sizeof(std::uint32_t); + + std::memcpy(&_buffer[write_position], value.data(), value.length()); + write_position += value_size; + } + _error = error_e::ERROR_OK; +} + +void config_command::deserialize(const std::vector<byte_t>& _buffer, error_e& _error) { + if (_buffer.size() < COMMAND_HEADER_SIZE) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) { + return; + } + if (get_version() != 0) { + _error = error_e::ERROR_UNKNOWN; + return; + } + std::size_t remaining = size_; + if (_buffer.size() < remaining) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + size_t read_position(COMMAND_POSITION_PAYLOAD); + std::function<std::string(bool&)> read = [&_buffer, &read_position, &remaining](bool& failed) { + if (remaining < sizeof(std::uint32_t)) { + failed = true; + return std::string(""); + } + size_t size = 0; + std::memcpy(&size, &_buffer[read_position], sizeof(std::uint32_t)); + remaining -= sizeof(std::uint32_t); + read_position += sizeof(std::uint32_t); + if (remaining < size) { + failed = true; + return std::string(""); + } + std::string value; + value.assign(&_buffer[read_position], &_buffer[read_position + size]); + remaining -= size; + read_position += size; + return value; + }; + while (remaining > 0) { + bool failed = false; + std::string key = read(failed); + if (failed) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + std::string value = read(failed); + if (failed) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + configs_[key] = value; + } + _error = error_e::ERROR_OK; +} + +void config_command::insert(const std::string& _key, const std::string&& _value) { + configs_.insert_or_assign(_key, std::move(_value)); +} + +bool config_command::contains(const std::string& _key) const { + return configs_.find(_key) != configs_.end(); +} + +const std::string& config_command::at(const std::string& _key) const { + return configs_.at(_key); +} + +const std::map<std::string, std::string, std::less<>>& config_command::configs() const { + return configs_; +} + +} // namespace vsomeip_v3::protocol diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/deregister_application_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/deregister_application_command.cpp new file mode 100644 index 00000000000..5cd6f8d7b3b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/deregister_application_command.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/deregister_application_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +deregister_application_command::deregister_application_command() + : simple_command(id_e::DEREGISTER_APPLICATION_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/distribute_security_policies_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/distribute_security_policies_command.cpp new file mode 100644 index 00000000000..63f6e70e61b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/distribute_security_policies_command.cpp @@ -0,0 +1,147 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/payload.hpp> + +#include "../include/distribute_security_policies_command.hpp" +#include "../../security/include/policy.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +distribute_security_policies_command::distribute_security_policies_command() + : command(id_e::DISTRIBUTE_SECURITY_POLICIES_ID) { +} + +void +distribute_security_policies_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + std::min(payload_.size(), size_t(std::numeric_limits<uint32_t>::max()))); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize (add) payload + size_t its_offset(COMMAND_HEADER_SIZE); + if (payload_.empty()) { // No policy data (--> set_payloads was not called) + std::memset(&_buffer[its_offset], 0, sizeof(uint32_t)); + } else { + std::memcpy(&_buffer[its_offset], payload_.data(), payload_.size()); + } +} + +void +distribute_security_policies_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(uint32_t) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + uint32_t its_policies_count; + std::memcpy(&its_policies_count, &_buffer[its_offset], + sizeof(its_policies_count)); + its_offset += sizeof(its_policies_count); + + for (uint32_t i = 0; i < its_policies_count; i++) { + + uint32_t its_policy_size; + + // Check that the buffer contains the full policy size + if (its_offset + sizeof(its_policy_size) > _buffer.size()) { + + policies_.clear(); + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + std::memcpy(&its_policy_size, &_buffer[its_offset], + sizeof(its_policy_size)); + its_offset += sizeof(its_policy_size); + + // Check that the buffer contains the full policy + if (its_offset + its_policy_size > _buffer.size()) { + + policies_.clear(); + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + const byte_t *its_policy_data = &_buffer[its_offset]; + + // set offset to the next policy + its_offset += its_policy_size; + + auto its_policy = std::make_shared<policy>(); + if (its_policy_size == 0 + || !its_policy->deserialize(its_policy_data, its_policy_size)) { + + _error = error_e::ERROR_UNKNOWN; + policies_.clear(); + return; + } + + policies_.insert(its_policy); + } +} + +std::set<std::shared_ptr<policy> > +distribute_security_policies_command::get_policies() const { + + return policies_; +} + +void +distribute_security_policies_command::set_payloads( + const std::map<uint32_t, std::shared_ptr<payload> > &_payloads) { + + uint32_t its_count(uint32_t(_payloads.size())); + for (uint32_t i = 0; i < sizeof(its_count); ++i) { + payload_.push_back( + reinterpret_cast<const byte_t*>(&its_count)[i]); + } + + for (const auto &its_uid_gid : _payloads) { + // policy payload length including gid and uid + std::uint32_t its_length(uint32_t(its_uid_gid.second->get_length())); + for (uint32_t i = 0; i < sizeof(its_length); ++i) { + payload_.push_back( + reinterpret_cast<const byte_t*>(&its_length)[i]); + } + // payload + payload_.insert(payload_.end(), its_uid_gid.second->get_data(), + its_uid_gid.second->get_data() + its_uid_gid.second->get_length()); + } +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/dummy_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/dummy_command.cpp new file mode 100644 index 00000000000..0ecc18f17bd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/dummy_command.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/dummy_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +dummy_command::dummy_command() + : command(id_e::UNKNOWN_ID) { + +} + +void +dummy_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + (void)_buffer; + _error = error_e::ERROR_NOT_ALLOWED; +} + +void +dummy_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (_buffer.size() < COMMAND_HEADER_SIZE) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + command::deserialize(_buffer, _error); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/expire_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/expire_command.cpp new file mode 100644 index 00000000000..06119016eff --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/expire_command.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/expire_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +expire_command::expire_command() + : subscribe_command_base(id_e::EXPIRE_ID) { +} + +void +expire_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // payload + subscribe_command_base::serialize(_buffer, _error); +} + +void +expire_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + subscribe_command_base::deserialize(_buffer, _error); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/multiple_services_command_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/multiple_services_command_base.cpp new file mode 100644 index 00000000000..35b32fc7c4d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/multiple_services_command_base.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/multiple_services_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +multiple_services_command_base::multiple_services_command_base(id_e _id) + : command(_id) { + +} + +void +multiple_services_command_base::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + (services_.size() + * (sizeof(service::service_) + sizeof(service::instance_) + + sizeof(service::major_) + sizeof(service::minor_)))); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + for (const auto &s : services_) { + std::memcpy(&_buffer[its_offset], &s.service_, sizeof(s.service_)); + its_offset += sizeof(s.service_); + std::memcpy(&_buffer[its_offset], &s.instance_, sizeof(s.instance_)); + its_offset += sizeof(s.instance_); + _buffer[its_offset] = s.major_; + its_offset += sizeof(s.major_); + std::memcpy(&_buffer[its_offset], &s.minor_, sizeof(s.minor_)); + its_offset += sizeof(s.minor_); + } +} + +void +multiple_services_command_base::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + size_t its_count = (_buffer.size() - its_offset) / + (sizeof(service::service_) + sizeof(service::instance_) + + sizeof(service::major_) + sizeof(service::minor_)); + + for (size_t i = 0; i < its_count; i++) { + service its_service; + + std::memcpy(&its_service.service_, &_buffer[its_offset], + sizeof(its_service.service_)); + its_offset += sizeof(its_service.service_); + std::memcpy(&its_service.instance_, &_buffer[its_offset], + sizeof(its_service.instance_)); + its_offset += sizeof(its_service.instance_); + std::memcpy(&its_service.major_, &_buffer[its_offset], + sizeof(its_service.major_)); + its_offset += sizeof(its_service.major_); + std::memcpy(&its_service.minor_, &_buffer[its_offset], + sizeof(its_service.minor_)); + its_offset += sizeof(its_service.minor_); + + services_.insert(its_service); + } +} + +std::set<service> +multiple_services_command_base::get_services() const { + + return services_; +} + +void +multiple_services_command_base::set_services(const std::set<service> &_services) { + + services_ = _services; +} + +void +multiple_services_command_base::add_service(const service &_service) { + + services_.insert(_service); +} + + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offer_service_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offer_service_command.cpp new file mode 100644 index 00000000000..286a6f74dea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offer_service_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/offer_service_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +offer_service_command::offer_service_command() + : service_command_base(id_e::OFFER_SERVICE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_request_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_request_command.cpp new file mode 100644 index 00000000000..639568b4229 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_request_command.cpp @@ -0,0 +1,78 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/offered_services_request_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +offered_services_request_command::offered_services_request_command() + : command(id_e::OFFERED_SERVICES_REQUEST_ID) { +} + +void +offered_services_request_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(offer_type_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(sizeof(offer_type_)); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + std::memcpy(&_buffer[COMMAND_POSITION_PAYLOAD], &offer_type_, + sizeof(offer_type_)); +} + +void +offered_services_request_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(offer_type_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&offer_type_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(offer_type_)); +} + +offer_type_e +offered_services_request_command::get_offer_type() const { + + return offer_type_; +} + +void +offered_services_request_command::set_offer_type(offer_type_e _offer_type) { + + offer_type_ = _offer_type; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_response_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_response_command.cpp new file mode 100644 index 00000000000..bc8df95a373 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/offered_services_response_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/offered_services_response_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +offered_services_response_command::offered_services_response_command() + : multiple_services_command_base(id_e::OFFERED_SERVICES_RESPONSE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/ping_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/ping_command.cpp new file mode 100644 index 00000000000..fab227b5507 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/ping_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/ping_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +ping_command::ping_command() + : simple_command(id_e::PING_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/pong_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/pong_command.cpp new file mode 100644 index 00000000000..8be1e90c62e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/pong_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/pong_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +pong_command::pong_command() + : simple_command(id_e::PONG_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_application_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_application_command.cpp new file mode 100644 index 00000000000..c4da7f60b19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_application_command.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/register_application_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +register_application_command::register_application_command() + : command(id_e::REGISTER_APPLICATION_ID), + port_(ILLEGAL_PORT) { + +} + +void +register_application_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(port_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(sizeof(port_)); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + std::memcpy(&_buffer[COMMAND_POSITION_PAYLOAD], &port_, + sizeof(port_)); + +} + +void +register_application_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(port_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&port_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(port_)); +} + +port_t +register_application_command::get_port() const { + + return port_; +} + +void +register_application_command::set_port(port_t _port) { + + port_ = _port; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_event.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_event.cpp new file mode 100644 index 00000000000..ecfd051f3a3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_event.cpp @@ -0,0 +1,118 @@ +#include "../include/register_event.hpp" +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { +namespace protocol { + +register_event::register_event(service_t service, instance_t instance, + event_t event, event_type_e event_type, + bool is_provided, reliability_type_e reliability, + bool is_cyclic, uint16_t num_eventg, + const std::set<eventgroup_t> &eventgroups): + service_(service), instance_(instance), event_(event), + event_type_(event_type), is_provided_(is_provided), + reliability_(reliability), is_cyclic_(is_cyclic), + num_eventg_(num_eventg), eventgroups_(eventgroups) { +} + +void +register_event::serialize(std::vector<byte_t> &_buffer, size_t &_offset, error_e &_error) const { + + size_t its_size(_offset + + sizeof(service_) + sizeof(instance_) + + sizeof(event_) + sizeof(event_type_) + + sizeof(is_provided_) + sizeof(reliability_) + + sizeof(is_cyclic_) + sizeof(num_eventg_)); + + // First check: Does the static part of the data fit into the buffer? + if (_buffer.size() < its_size) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + std::memcpy(&_buffer[_offset], &service_, sizeof(service_)); + _offset += sizeof(service_); + std::memcpy(&_buffer[_offset], &instance_, sizeof(instance_)); + _offset += sizeof(instance_); + std::memcpy(&_buffer[_offset], &event_, sizeof(event_)); + _offset += sizeof(event_); + _buffer[_offset] = static_cast<byte_t>(event_type_); + _offset += sizeof(event_type_); + _buffer[_offset] = static_cast<byte_t>(is_provided_); + _offset += sizeof(is_provided_); + _buffer[_offset] = static_cast<byte_t>(reliability_); + _offset += sizeof(reliability_); + _buffer[_offset] = static_cast<byte_t>(is_cyclic_); + _offset += sizeof(is_cyclic_); + std::memcpy(&_buffer[_offset], &num_eventg_, sizeof(num_eventg_)); + _offset += sizeof(num_eventg_); + + // Second check: Does the dynamic part of the data fit into the buffer? + if (_buffer.size() < _offset + (num_eventg_ * sizeof(eventgroup_t))) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + for (const auto g : eventgroups_) { + std::memcpy(&_buffer[_offset], &g, sizeof(g)); + _offset += sizeof(g); + } +} + +void +register_event::deserialize(const std::vector<byte_t> &_buffer, size_t &_offset, error_e &_error) { + + size_t its_size(_offset + + sizeof(service_) + sizeof(instance_) + + sizeof(event_) + sizeof(event_type_) + + sizeof(is_provided_) + sizeof(reliability_) + + sizeof(is_cyclic_) + sizeof(num_eventg_)); + + // First check: Does the buffer contain the full static part of the data? + if (_buffer.size() < its_size) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + std::memcpy(&service_, &_buffer[_offset], sizeof(service_)); + _offset += sizeof(service_); + std::memcpy(&instance_, &_buffer[_offset], sizeof(instance_)); + _offset += sizeof(instance_); + std::memcpy(&event_, &_buffer[_offset], sizeof(event_)); + _offset += sizeof(event_); + event_type_ = static_cast<event_type_e>(_buffer[_offset]); + _offset += sizeof(event_type_); + is_provided_ = static_cast<bool>(_buffer[_offset]); + _offset += sizeof(is_provided_); + reliability_ = static_cast<reliability_type_e>(_buffer[_offset]); + _offset += sizeof(reliability_); + is_cyclic_ = static_cast<bool>(_buffer[_offset]); + _offset += sizeof(is_cyclic_); + std::memcpy(&num_eventg_, &_buffer[_offset], sizeof(num_eventg_)); + _offset += sizeof(num_eventg_); + + // Second check: Does the buffer contain the full dynamic part of the data? + if (_buffer.size() < _offset + (num_eventg_ * sizeof(eventgroup_t))) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + eventgroups_.clear(); + for (size_t i = 0; i < num_eventg_; i++) { + eventgroup_t its_g; + std::memcpy(&its_g, &_buffer[_offset], sizeof(its_g)); + _offset += sizeof(its_g); + + eventgroups_.insert(its_g); + } +} + +void +register_event::set_eventgroups(const std::set<eventgroup_t> &_eventgroups) { + + eventgroups_ = _eventgroups; + num_eventg_ = (uint16_t)eventgroups_.size(); +} + +} // namespace protocol +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_events_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_events_command.cpp new file mode 100644 index 00000000000..9f8a0c23e98 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/register_events_command.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/register_events_command.hpp" +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { +namespace protocol { + +register_events_command::register_events_command() + : command(id_e::REGISTER_EVENT_ID) { +} + +bool +register_events_command::add_registration(const register_event &_register_event) { + + size_t its_size(size_ + COMMAND_HEADER_SIZE + + sizeof(_register_event.get_service()) + sizeof(_register_event.get_instance()) + + sizeof(_register_event.get_event()) + sizeof(_register_event.get_event_type()) + + sizeof(_register_event.is_provided()) + sizeof(_register_event.get_reliability()) + + sizeof(_register_event.is_cyclic()) + sizeof(_register_event.get_num_eventgroups()) + + (_register_event.get_num_eventgroups() * sizeof(eventgroup_t) )); + + // check size + if (its_size > std::numeric_limits<command_size_t>::max()) + return false; + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + registrations_.push_back(_register_event); + + return true; +} + +void +register_events_command::serialize(std::vector<byte_t> &_buffer, error_e &_error) const { + + if (size_ + COMMAND_HEADER_SIZE > std::numeric_limits<command_size_t>::max()) { + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(size_+COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + for(auto ® : registrations_) { + reg.serialize(_buffer, its_offset, _error); + if (_error != error_e::ERROR_OK) + return; + } +} + +void +register_events_command::deserialize(const std::vector<byte_t> &_buffer, error_e &_error) { + registrations_.clear(); + + if(_buffer.size() < COMMAND_HEADER_SIZE) { + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + size_t its_offset(COMMAND_HEADER_SIZE); + + while (its_offset < _buffer.size()) { + register_event event_command; + event_command.deserialize(_buffer, its_offset, _error); + if (_error != error_e::ERROR_OK) + return; + + registrations_.push_back(event_command); + } +} + +std::size_t +register_events_command::get_num_registrations() const { + + return registrations_.size(); +} + +bool +register_events_command::get_registration_at(std::size_t _position, register_event & _reg) const { + + if(_position < registrations_.size()) { + _reg = registrations_[_position]; + return true; + } + return false; +} + +} // namespace protocol +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/registered_ack_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/registered_ack_command.cpp new file mode 100644 index 00000000000..a9df5d3f797 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/registered_ack_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/registered_ack_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +registered_ack_command::registered_ack_command() + : simple_command(id_e::REGISTERED_ACK_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/release_service_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/release_service_command.cpp new file mode 100644 index 00000000000..d982d396a8f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/release_service_command.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/release_service_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +release_service_command::release_service_command() + : command(id_e::RELEASE_SERVICE_ID) { + +} + +void +release_service_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service::service_) + sizeof(service::instance_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &service_.service_, sizeof(service_.service_)); + its_offset += sizeof(service_.service_); + std::memcpy(&_buffer[its_offset], &service_.instance_, sizeof(service_.instance_)); +} + +void +release_service_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service::service_) + sizeof(service::instance_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&service_.service_, &_buffer[its_offset], + sizeof(service_.service_)); + its_offset += sizeof(service_.service_); + std::memcpy(&service_.instance_, &_buffer[its_offset], + sizeof(service_.instance_)); +} + +service_t +release_service_command::get_service() const { + + return service_.service_; +} + +void +release_service_command::set_service(service_t _service) { + + service_.service_ = _service; +} + +instance_t +release_service_command::get_instance() const { + + return service_.instance_; +} + +void +release_service_command::set_instance(instance_t _instance) { + + service_.instance_ = _instance; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_command.cpp new file mode 100644 index 00000000000..0b68395c219 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_command.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/remove_security_policy_command.hpp" +#include "../../security/include/policy.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +remove_security_policy_command::remove_security_policy_command() + : command(id_e::REMOVE_SECURITY_POLICY_ID) { +} + +void +remove_security_policy_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(update_id_) + + sizeof(uid_) + sizeof(gid_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &update_id_, sizeof(update_id_)); + its_offset += sizeof(update_id_); + std::memcpy(&_buffer[its_offset], &uid_, sizeof(uid_)); + its_offset += sizeof(uid_); + std::memcpy(&_buffer[its_offset], &gid_, sizeof(gid_)); +} + +void +remove_security_policy_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(update_id_) + + sizeof(uid_) + sizeof(gid_t) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&update_id_, &_buffer[its_offset], sizeof(update_id_)); + its_offset += sizeof(update_id_); + std::memcpy(&uid_, &_buffer[its_offset], sizeof(uid_)); + its_offset += sizeof(uid_); + std::memcpy(&gid_, &_buffer[its_offset], sizeof(gid_)); +} + +uint32_t +remove_security_policy_command::get_update_id() const { + + return update_id_; +} + +void +remove_security_policy_command::set_update_id(uint32_t _update_id) { + + update_id_ = _update_id; +} + + +uid_t +remove_security_policy_command::get_uid() const { + + return uid_; +} + +void +remove_security_policy_command::set_uid(uid_t _uid) { + + uid_ = _uid; +} + +gid_t +remove_security_policy_command::get_gid() const { + + return gid_; +} + +void +remove_security_policy_command::set_gid(gid_t _gid) { + + gid_ = _gid; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_response_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_response_command.cpp new file mode 100644 index 00000000000..ce8ab0b28be --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/remove_security_policy_response_command.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/remove_security_policy_response_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +remove_security_policy_response_command::remove_security_policy_response_command() + : security_policy_response_command_base( + id_e::REMOVE_SECURITY_POLICY_RESPONSE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/request_service_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/request_service_command.cpp new file mode 100644 index 00000000000..c98f8eb22dc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/request_service_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/request_service_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +request_service_command::request_service_command() + : multiple_services_command_base(id_e::REQUEST_SERVICE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/resend_provided_events_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/resend_provided_events_command.cpp new file mode 100644 index 00000000000..39f9c4ea8d5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/resend_provided_events_command.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/resend_provided_events_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +resend_provided_events_command::resend_provided_events_command() + : command(id_e::RESEND_PROVIDED_EVENTS_ID) { + +} + +void +resend_provided_events_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(remote_offer_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(sizeof(remote_offer_id_)); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + std::memcpy(&_buffer[COMMAND_POSITION_PAYLOAD], &remote_offer_id_, + sizeof(remote_offer_id_)); +} + +void +resend_provided_events_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(remote_offer_id_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&remote_offer_id_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(remote_offer_id_)); +} + +pending_remote_offer_id_t +resend_provided_events_command::get_remote_offer_id() const { + + return remote_offer_id_; +} + +void +resend_provided_events_command::set_remote_offer_id( + pending_remote_offer_id_t _remote_offer_id) { + + remote_offer_id_ = _remote_offer_id; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_command.cpp new file mode 100644 index 00000000000..3ddef84bd07 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_command.cpp @@ -0,0 +1,98 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/routing_info_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +routing_info_command::routing_info_command() + : command(id_e::ROUTING_INFO_ID) { + +} + +void +routing_info_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE); + for (const auto &e : entries_) + its_size += e.get_size(); + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t _index(COMMAND_HEADER_SIZE); + for (const auto &e : entries_) { + e.serialize(_buffer, _index, _error); + if (_error != error_e::ERROR_OK) { + _buffer.clear(); + return; + } + } +} + +void +routing_info_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + + // deserialize payload + size_t its_index(COMMAND_HEADER_SIZE); + while (its_index < _buffer.size()) { + + routing_info_entry its_entry; + its_entry.deserialize(_buffer, its_index, _error); + + if (_error == error_e::ERROR_OK) + entries_.emplace_back(its_entry); + else + break; + } +} + +// specific +const std::vector<routing_info_entry> & +routing_info_command::get_entries() const { + + return entries_; +} + +void +routing_info_command::set_entries(std::vector<routing_info_entry> &&_entries) { + + entries_ = std::move(_entries); +} + +void +routing_info_command::add_entry(const routing_info_entry &_entry) { + + entries_.push_back(_entry); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_entry.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_entry.cpp new file mode 100644 index 00000000000..9ca006d1283 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/routing_info_entry.cpp @@ -0,0 +1,304 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> +#include <limits> + +#include <boost/asio/ip/address_v4.hpp> +#include <boost/asio/ip/address_v6.hpp> + +#include "../include/routing_info_entry.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +routing_info_entry::routing_info_entry() + : type_(routing_info_entry_type_e::RIE_UNKNOWN), + port_(0) { + +} + +routing_info_entry::routing_info_entry(const routing_info_entry &_source) + : type_(_source.type_), + client_(_source.client_), + address_(_source.address_), + port_(_source.port_), + services_(_source.services_) { + +} + +void +routing_info_entry::serialize(std::vector<byte_t> &_buffer, + size_t &_index, error_e &_error) const { + + _buffer[_index] = static_cast<byte_t>(type_); + _index += sizeof(type_); + + // Size is overall size - size field - command type + size_t its_size = get_size() - sizeof(uint32_t) - 1; + if (its_size > std::numeric_limits<uint32_t>::max()) { + + _error = error_e::ERROR_MALFORMED; + return; + } + + uint32_t its_size32(static_cast<uint32_t>(its_size)); + std::memcpy(&_buffer[_index], &its_size32, sizeof(its_size32)); + _index += sizeof(its_size32); + + uint32_t its_client_size(sizeof(client_)); + if (!address_.is_unspecified()) { + if (address_.is_v4()) { + its_client_size += uint32_t(sizeof(boost::asio::ip::address_v4::bytes_type) + + sizeof(port_)); + } else { + its_client_size += uint32_t(sizeof(boost::asio::ip::address_v6::bytes_type) + + sizeof(port_)); + } + } + + if (type_ > routing_info_entry_type_e::RIE_DELETE_CLIENT) { + + std::memcpy(&_buffer[_index], &its_client_size, sizeof(its_client_size)); + _index += sizeof(its_client_size); + } + + std::memcpy(&_buffer[_index], &client_, sizeof(client_)); + _index += sizeof(client_); + + if (!address_.is_unspecified()) { + + if (address_.is_v4()) { + std::memcpy(&_buffer[_index], address_.to_v4().to_bytes().data(), + sizeof(boost::asio::ip::address_v4::bytes_type)); + _index += sizeof(boost::asio::ip::address_v4::bytes_type); + } else { + std::memcpy(&_buffer[_index], address_.to_v6().to_bytes().data(), + sizeof(boost::asio::ip::address_v6::bytes_type)); + _index += sizeof(boost::asio::ip::address_v6::bytes_type); + } + std::memcpy(&_buffer[_index], &port_, sizeof(port_)); + _index += sizeof(port_); + } + + if (type_ > routing_info_entry_type_e::RIE_DELETE_CLIENT) { + + its_size = (services_.size() * + (sizeof(service_t) + sizeof(instance_t) + + sizeof(major_version_t) + sizeof(minor_version_t))); + + if (its_size > std::numeric_limits<uint32_t>::max()) { + + _error = error_e::ERROR_MALFORMED; + return; + } + + its_size32 = static_cast<uint32_t>(its_size); + std::memcpy(&_buffer[_index], &its_size32, sizeof(its_size32)); + _index += sizeof(its_size32); + + for (const auto &s : services_) { + + std::memcpy(&_buffer[_index], &s.service_, sizeof(s.service_)); + _index += sizeof(s.service_); + std::memcpy(&_buffer[_index], &s.instance_, sizeof(s.instance_)); + _index += sizeof(s.instance_); + std::memcpy(&_buffer[_index], &s.major_, sizeof(s.major_)); + _index += sizeof(s.major_); + std::memcpy(&_buffer[_index], &s.minor_, sizeof(s.minor_)); + _index += sizeof(s.minor_); + } + } +} + +void +routing_info_entry::deserialize(const std::vector<byte_t> &_buffer, + size_t &_index, error_e &_error) { + + uint32_t its_size; + uint32_t its_client_size; + + if (_buffer.size() < _index + sizeof(type_) + sizeof(its_size) + + sizeof(client_)) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + type_ = static_cast<routing_info_entry_type_e>(_buffer[_index++]); + if (type_ == routing_info_entry_type_e::RIE_UNKNOWN) { + + _error = error_e::ERROR_MALFORMED; + return; + } + + std::memcpy(&its_size, &_buffer[_index], sizeof(its_size)); + _index += sizeof(its_size); + + if (type_ > routing_info_entry_type_e::RIE_DELETE_CLIENT) { + std::memcpy(&its_client_size, &_buffer[_index], sizeof(its_client_size)); + _index += sizeof(its_client_size); + } else { + its_client_size = its_size; + } + + std::memcpy(&client_, &_buffer[_index], sizeof(client_)); + _index += sizeof(client_); + + if (its_client_size > sizeof(client_)) { + + uint32_t its_address_size = its_client_size + - uint32_t(sizeof(client_t) + sizeof(port_)); + + if (its_address_size == sizeof(boost::asio::ip::address_v4::bytes_type)) { + + boost::asio::ip::address_v4::bytes_type its_array; + std::memcpy(&its_array, &_buffer[_index], its_array.size()); + address_ = boost::asio::ip::address_v4(its_array); + _index += its_array.size(); + + } else if (its_address_size == sizeof(boost::asio::ip::address_v6::bytes_type)) { + + boost::asio::ip::address_v6::bytes_type its_array; + std::memcpy(&its_array, &_buffer[_index], its_array.size()); + address_ = boost::asio::ip::address_v6(its_array); + _index += its_array.size(); + + } else { + + _error = error_e::ERROR_MALFORMED; + return; + } + + std::memcpy(&port_, &_buffer[_index], sizeof(port_)); + _index += sizeof(port_); + } + + if (type_ > routing_info_entry_type_e::RIE_DELETE_CLIENT) { + + if (_buffer.size() < _index + sizeof(its_size)) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + std::memcpy(&its_size, &_buffer[_index], sizeof(its_size)); + _index += sizeof(its_size); + + if (_buffer.size() < _index + its_size) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + size_t its_n = (its_size / + (sizeof(service_t) + sizeof(instance_t) + + sizeof(major_version_t) + sizeof(minor_version_t))); + + for (size_t i = 0; i < its_n; i++) { + + service its_service; + std::memcpy(&its_service.service_, &_buffer[_index], sizeof(its_service.service_)); + _index += sizeof(its_service.service_); + std::memcpy(&its_service.instance_, &_buffer[_index], sizeof(its_service.instance_)); + _index += sizeof(its_service.instance_); + its_service.major_ = static_cast<major_version_t>(_buffer[_index]); + _index += sizeof(its_service.major_); + std::memcpy(&its_service.minor_, &_buffer[_index], sizeof(its_service.minor_)); + _index += sizeof(its_service.minor_); + + services_.emplace_back(its_service); + } + } +} + +routing_info_entry_type_e +routing_info_entry::get_type() const { + + return type_; +} + +void +routing_info_entry::set_type(routing_info_entry_type_e _type) { + + type_ = _type; +} + +size_t +routing_info_entry::get_size() const { + + size_t its_size(ROUTING_INFO_ENTRY_HEADER_SIZE); + + if (!address_.is_unspecified()) { + if (address_.is_v4()) { + its_size += (sizeof(boost::asio::ip::address_v4::bytes_type) + + sizeof(port_)); + } else { + its_size += (sizeof(boost::asio::ip::address_v6::bytes_type) + + sizeof(port_)); + } + } + + if (type_ > routing_info_entry_type_e::RIE_DELETE_CLIENT) { + its_size += sizeof(uint32_t); // size of the client info + its_size += sizeof(uint32_t); // size of the services array + its_size += (services_.size() * + (sizeof(service_t) + sizeof(instance_t) + + sizeof(major_version_t) + sizeof(minor_version_t))); + } + + return its_size; +} + +client_t +routing_info_entry::get_client() const { + + return client_; +} + +void +routing_info_entry::set_client(client_t _client) { + + client_ = _client; +} + +boost::asio::ip::address +routing_info_entry::get_address() const { + + return address_; +} + +void +routing_info_entry::set_address(const boost::asio::ip::address &_address) { + + address_ = _address; +} + +port_t +routing_info_entry::get_port() const { + + return port_; +} + +void +routing_info_entry::set_port(port_t _port) { + + port_ = _port; +} + +const std::vector<service> & +routing_info_entry::get_services() const { + + return services_; +} + +void +routing_info_entry::add_service(const service &_service) { + + services_.push_back(_service); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/security_policy_response_command_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/security_policy_response_command_base.cpp new file mode 100644 index 00000000000..6b9ba2c1de0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/security_policy_response_command_base.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/security_policy_response_command_base.hpp" +#include "../../security/include/policy.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +security_policy_response_command_base::security_policy_response_command_base( + id_e _id) + : command(_id) { +} + +void +security_policy_response_command_base::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(update_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &update_id_, sizeof(update_id_)); +} + +void +security_policy_response_command_base::deserialize( + const std::vector<byte_t> &_buffer, error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(update_id_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&update_id_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(update_id_)); +} + +uint32_t +security_policy_response_command_base::get_update_id() const { + + return update_id_; +} + +void +security_policy_response_command_base::set_update_id(uint32_t _update_id) { + + update_id_ = _update_id; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/send_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/send_command.cpp new file mode 100644 index 00000000000..7959744faf7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/send_command.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/send_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +send_command::send_command(id_e _id) + : command(_id) { +} + +instance_t +send_command::get_instance() const { + + return instance_; +} + +void +send_command::set_instance(instance_t _instance) { + + instance_ = _instance; +} + +bool +send_command::is_reliable() const { + + return is_reliable_; +} + +void +send_command::set_reliable(bool _is_reliable) { + + is_reliable_ = _is_reliable; +} + +uint8_t +send_command::get_status() const { + + return status_; +} + +void +send_command::set_status(uint8_t _status) { + + status_ = _status; +} + +client_t +send_command::get_target() const { + + return target_; +} + +void +send_command::set_target(client_t _target) { + + target_ = _target; +} + +std::vector<byte_t> +send_command::get_message() const { + + return message_; +} + +void +send_command::set_message(const std::vector<byte_t> &_message) { + + message_ = std::move(_message); +} + +void +send_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(instance_) + + sizeof(is_reliable_) + sizeof(status_) + + sizeof(target_) + message_.size()); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&_buffer[its_offset], &instance_, sizeof(instance_)); + its_offset += sizeof(instance_); + _buffer[its_offset] = static_cast<byte_t>(is_reliable_); + its_offset += sizeof(is_reliable_); + _buffer[its_offset] = static_cast<byte_t>(status_); + its_offset += sizeof(status_); + std::memcpy(&_buffer[its_offset], &target_, sizeof(target_)); + its_offset += sizeof(target_); + std::memcpy(&_buffer[its_offset], &message_[0], message_.size()); +} + +void +send_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(instance_) + + sizeof(is_reliable_) + sizeof(status_) + + sizeof(target_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&instance_, &_buffer[its_offset], sizeof(instance_)); + its_offset += sizeof(instance_); + is_reliable_ = static_cast<bool>(_buffer[its_offset]); + its_offset += sizeof(is_reliable_); + status_ = static_cast<uint8_t>(_buffer[its_offset]); + its_offset += sizeof(status_); + std::memcpy(&target_, &_buffer[its_offset], sizeof(target_)); + its_offset += sizeof(target_); + message_.resize(_buffer.size() - its_offset); + std::memcpy(&message_[0], &_buffer[its_offset], message_.size()); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/service_command_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/service_command_base.cpp new file mode 100644 index 00000000000..ae270f2e0fc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/service_command_base.cpp @@ -0,0 +1,130 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/service_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +service_command_base::service_command_base(id_e _id) + : command(_id) { +} + +service_t +service_command_base::get_service() const { + + return service_.service_; +} + +void +service_command_base::set_service(service_t _service) { + + service_.service_ = _service; +} + +instance_t +service_command_base::get_instance() const { + + return service_.instance_; +} + +void +service_command_base::set_instance(instance_t _instance) { + + service_.instance_ = _instance; +} + +major_version_t +service_command_base::get_major() const { + + return service_.major_; +} + +void +service_command_base::set_major(major_version_t _major) { + + service_.major_ = _major; +} + +minor_version_t +service_command_base::get_minor() const { + + return service_.minor_; +} + +void +service_command_base::set_minor(minor_version_t _minor) { + + service_.minor_ = _minor; +} + +void +service_command_base::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_.service_) + sizeof(service_.instance_) + + sizeof(service_.major_) + sizeof(service_.minor_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&_buffer[its_offset], &service_.service_, sizeof(service_.service_)); + its_offset += sizeof(service_.service_); + std::memcpy(&_buffer[its_offset], &service_.instance_, sizeof(service_.instance_)); + its_offset += sizeof(service_.instance_); + _buffer[its_offset] = service_.major_; + its_offset += sizeof(service_.major_); + std::memcpy(&_buffer[its_offset], &service_.minor_, sizeof(service_.minor_)); +} + +void +service_command_base::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_.service_) + sizeof(service_.instance_) + + sizeof(service_.major_) + sizeof(service_.minor_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&service_.service_, &_buffer[its_offset], sizeof(service_.service_)); + its_offset += sizeof(service_.service_); + std::memcpy(&service_.instance_, &_buffer[its_offset], sizeof(service_.instance_)); + its_offset += sizeof(service_.instance_); + service_.major_ = _buffer[its_offset]; + its_offset += sizeof(service_.major_); + std::memcpy(&service_.minor_, &_buffer[its_offset], sizeof(service_.minor_)); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/simple_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/simple_command.cpp new file mode 100644 index 00000000000..90760127aa9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/simple_command.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/simple_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +simple_command::simple_command(id_e _id) + : command(_id) { + +} + +void +simple_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + // no size check as we know this is small enough + + // resize buffer + _buffer.resize(COMMAND_HEADER_SIZE); + + // set size + size_ = 0; + + // serialize header + command::serialize(_buffer, _error); +} + +void +simple_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (_buffer.size() < COMMAND_HEADER_SIZE) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + command::deserialize(_buffer, _error); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/stop_offer_service_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/stop_offer_service_command.cpp new file mode 100644 index 00000000000..c12a20d57ad --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/stop_offer_service_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/stop_offer_service_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +stop_offer_service_command::stop_offer_service_command() + : service_command_base(id_e::STOP_OFFER_SERVICE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command.cpp new file mode 100644 index 00000000000..12fe1cd49b1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/subscribe_ack_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +subscribe_ack_command::subscribe_ack_command() + : subscribe_ack_command_base(id_e::SUBSCRIBE_ACK_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command_base.cpp new file mode 100644 index 00000000000..2a8897232ee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_ack_command_base.cpp @@ -0,0 +1,174 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/subscribe_ack_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +subscribe_ack_command_base::subscribe_ack_command_base(id_e _id) + : command(_id), + service_(ANY_SERVICE), + instance_(ANY_INSTANCE), + eventgroup_(0), + subscriber_(0), + event_(ANY_EVENT), + pending_id_(0) { +} + +service_t +subscribe_ack_command_base::get_service() const { + + return service_; +} + +void +subscribe_ack_command_base::set_service(service_t _service) { + + service_ = _service; +} + +instance_t +subscribe_ack_command_base::get_instance() const { + + return instance_; +} + +void +subscribe_ack_command_base::set_instance(instance_t _instance) { + + instance_ = _instance; +} + +eventgroup_t +subscribe_ack_command_base::get_eventgroup() const { + + return eventgroup_; +} + +void +subscribe_ack_command_base::set_eventgroup(eventgroup_t _eventgroup) { + + eventgroup_ = _eventgroup; +} + +client_t +subscribe_ack_command_base::get_subscriber() const { + + return subscriber_; +} + +void +subscribe_ack_command_base::set_subscriber(client_t _subscriber) { + + subscriber_ = _subscriber; +} + +event_t +subscribe_ack_command_base::get_event() const { + + return event_; +} + +void +subscribe_ack_command_base::set_event(event_t _event) { + + event_ = _event; +} + +pending_id_t +subscribe_ack_command_base::get_pending_id() const { + + return pending_id_; +} + +void +subscribe_ack_command_base::set_pending_id(pending_id_t _pending_id) { + + pending_id_ = _pending_id; +} + +void +subscribe_ack_command_base::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(subscriber_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&_buffer[its_offset], &service_, sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&_buffer[its_offset], &instance_, sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&_buffer[its_offset], &eventgroup_, sizeof(eventgroup_)); + its_offset += sizeof(instance_); + std::memcpy(&_buffer[its_offset], &subscriber_, sizeof(subscriber_)); + its_offset += sizeof(subscriber_); + std::memcpy(&_buffer[its_offset], &event_, sizeof(event_)); + its_offset += sizeof(event_); + std::memcpy(&_buffer[its_offset], &pending_id_, sizeof(pending_id_)); +} + +void +subscribe_ack_command_base::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(subscriber_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&service_, &_buffer[its_offset], sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&instance_, &_buffer[its_offset], sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&eventgroup_, &_buffer[its_offset], sizeof(eventgroup_)); + its_offset += sizeof(eventgroup_); + std::memcpy(&subscriber_, &_buffer[its_offset], sizeof(subscriber_)); + its_offset += sizeof(subscriber_); + std::memcpy(&event_, &_buffer[its_offset], sizeof(event_)); + its_offset += sizeof(event_); + std::memcpy(&pending_id_, &_buffer[its_offset], sizeof(pending_id_)); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command.cpp new file mode 100644 index 00000000000..0bc85b99c1a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/subscribe_command.hpp" +#include "../../configuration/include/debounce_filter_impl.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +subscribe_command::subscribe_command() + : subscribe_command_base(id_e::SUBSCRIBE_ID) { +} + +std::shared_ptr<debounce_filter_impl_t> +subscribe_command::get_filter() const { + + return filter_; +} + +void +subscribe_command::set_filter( + const std::shared_ptr<debounce_filter_impl_t> &_filter) { + + filter_ = _filter; +} + +void +subscribe_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + size_t its_offset(its_size); + + if (filter_) { + its_size += sizeof(filter_->on_change_) + + sizeof(filter_->on_change_resets_interval_) + + sizeof(filter_->interval_) + + (filter_->ignore_.size() * (sizeof(size_t) + sizeof(byte_t))) + + sizeof(filter_->send_current_value_after_); + } + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + subscribe_command_base::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + if (filter_) { + + _buffer[its_offset] = static_cast<byte_t>(filter_->on_change_); + its_offset += sizeof(filter_->on_change_); + _buffer[its_offset] = static_cast<byte_t>(filter_->on_change_resets_interval_); + its_offset += sizeof(filter_->on_change_resets_interval_); + std::memcpy(&_buffer[its_offset], &filter_->interval_, sizeof(filter_->interval_)); + its_offset += sizeof(filter_->interval_); + for (const auto &its_ignore : filter_->ignore_) { + std::memcpy(&_buffer[its_offset], &its_ignore.first, sizeof(size_t)); + its_offset += sizeof(size_t); + _buffer[its_offset] = its_ignore.second; + its_offset += sizeof(byte_t); + } + _buffer[its_offset] = static_cast<byte_t>(filter_->send_current_value_after_); + its_offset += sizeof(filter_->send_current_value_after_); + } +} + +void +subscribe_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize subscription + subscribe_command_base::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize filter + size_t its_offset(its_size); + if (_buffer.size() - its_offset + >= sizeof(bool) + sizeof(bool) + sizeof(int64_t)) { + + filter_ = std::make_shared<debounce_filter_impl_t>(); + std::memcpy(&filter_->on_change_, &_buffer[its_offset], sizeof(filter_->on_change_)); + its_offset += sizeof(filter_->on_change_); + std::memcpy(&filter_->on_change_resets_interval_, &_buffer[its_offset], sizeof(filter_->on_change_resets_interval_)); + its_offset += sizeof(filter_->on_change_resets_interval_); + std::memcpy(&filter_->interval_, &_buffer[its_offset], sizeof(filter_->interval_)); + its_offset += sizeof(filter_->interval_); + + while (_buffer.size() - its_offset + >= sizeof(size_t) + sizeof(byte_t)) { + + size_t its_key; + byte_t its_value; + + std::memcpy(&its_key, &_buffer[its_offset], sizeof(its_key)); + if (filter_->ignore_.find(its_key) != filter_->ignore_.end()) { + + _error = error_e::ERROR_MALFORMED; + return; + } + + its_offset += sizeof(its_key); + its_value = _buffer[its_offset]; + its_offset += sizeof(its_value); + + filter_->ignore_.emplace(std::make_pair(its_key, its_value)); + } + + std::memcpy(&filter_->send_current_value_after_, &_buffer[its_offset], sizeof(filter_->send_current_value_after_)); + its_offset += sizeof(filter_->send_current_value_after_); + } +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command_base.cpp new file mode 100644 index 00000000000..cd5644a5396 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_command_base.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/subscribe_command_base.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +subscribe_command_base::subscribe_command_base(id_e _id) + : command(_id), + service_(ANY_SERVICE), + instance_(ANY_INSTANCE), + eventgroup_(0), + major_(ANY_MAJOR), + event_(ANY_EVENT), + pending_id_(0) { +} + +service_t +subscribe_command_base::get_service() const { + + return service_; +} + +void +subscribe_command_base::set_service(service_t _service) { + + service_ = _service; +} + +instance_t +subscribe_command_base::get_instance() const { + + return instance_; +} + +void +subscribe_command_base::set_instance(instance_t _instance) { + + instance_ = _instance; +} + +eventgroup_t +subscribe_command_base::get_eventgroup() const { + + return eventgroup_; +} + +void +subscribe_command_base::set_eventgroup(eventgroup_t _eventgroup) { + + eventgroup_ = _eventgroup; +} + +major_version_t +subscribe_command_base::get_major() const { + + return major_; +} + +void +subscribe_command_base::set_major(major_version_t _major) { + + major_ = _major; +} + +event_t +subscribe_command_base::get_event() const { + + return event_; +} + +void +subscribe_command_base::set_event(event_t _event) { + + event_ = _event; +} + +pending_id_t +subscribe_command_base::get_pending_id() const { + + return pending_id_; +} + +void +subscribe_command_base::set_pending_id(pending_id_t _pending_id) { + + pending_id_ = _pending_id; +} + +void +subscribe_command_base::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&_buffer[its_offset], &service_, sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&_buffer[its_offset], &instance_, sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&_buffer[its_offset], &eventgroup_, sizeof(eventgroup_)); + its_offset += sizeof(instance_); + _buffer[its_offset] = major_; + its_offset += sizeof(major_); + std::memcpy(&_buffer[its_offset], &event_, sizeof(event_)); + its_offset += sizeof(event_); + std::memcpy(&_buffer[its_offset], &pending_id_, sizeof(pending_id_)); +} + +void +subscribe_command_base::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + size_t its_offset(COMMAND_POSITION_PAYLOAD); + std::memcpy(&service_, &_buffer[its_offset], sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&instance_, &_buffer[its_offset], sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&eventgroup_, &_buffer[its_offset], sizeof(eventgroup_)); + its_offset += sizeof(eventgroup_); + major_ = _buffer[its_offset]; + its_offset += sizeof(major_); + std::memcpy(&event_, &_buffer[its_offset], sizeof(event_)); + its_offset += sizeof(event_); + std::memcpy(&pending_id_, &_buffer[its_offset], sizeof(pending_id_)); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_nack_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_nack_command.cpp new file mode 100644 index 00000000000..b009dadbfa7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/subscribe_nack_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/subscribe_nack_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +subscribe_nack_command::subscribe_nack_command() + : subscribe_ack_command_base(id_e::SUBSCRIBE_NACK_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/suspend_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/suspend_command.cpp new file mode 100644 index 00000000000..4f780f08ef1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/suspend_command.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/suspend_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +suspend_command::suspend_command() + : simple_command(id_e::SUSPEND_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unregister_event_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unregister_event_command.cpp new file mode 100644 index 00000000000..ff9813c3193 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unregister_event_command.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/unregister_event_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +unregister_event_command::unregister_event_command() + : command(id_e::UNREGISTER_EVENT_ID), + service_(ANY_SERVICE), + instance_(ANY_INSTANCE), + event_(ANY_EVENT), + is_provided_(false) { +} + +service_t +unregister_event_command::get_service() const { + + return service_; +} + +void +unregister_event_command::set_service(service_t _service) { + + service_ = _service; +} + +instance_t +unregister_event_command::get_instance() const { + + return instance_; +} + +void +unregister_event_command::set_instance(instance_t _instance) { + + instance_ = _instance; +} + +event_t +unregister_event_command::get_event() const { + + return event_; +} + +void +unregister_event_command::set_event(event_t _event) { + + event_ = _event; +} + + +bool +unregister_event_command::is_provided() const { + + return is_provided_; +} + +void +unregister_event_command::set_provided(bool _is_provided) { + + is_provided_ = _is_provided; +} + +void +unregister_event_command::serialize(std::vector<byte_t> &_buffer, error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(event_) + sizeof(is_provided_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &service_, sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&_buffer[its_offset], &instance_, sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&_buffer[its_offset], &event_, sizeof(event_)); + its_offset += sizeof(event_); + _buffer[its_offset] = static_cast<byte_t>(is_provided_); +} + +void +unregister_event_command::deserialize(const std::vector<byte_t> &_buffer, error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(event_) + sizeof(is_provided_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&service_, &_buffer[its_offset], sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&instance_, &_buffer[its_offset], sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&event_, &_buffer[its_offset], sizeof(event_)); + its_offset += sizeof(event_); + is_provided_ = static_cast<bool>(_buffer[its_offset]); +} + +} // namespace protocol +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_ack_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_ack_command.cpp new file mode 100644 index 00000000000..ab7138d1f70 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_ack_command.cpp @@ -0,0 +1,139 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/unsubscribe_ack_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +unsubscribe_ack_command::unsubscribe_ack_command() + : command(id_e::UNSUBSCRIBE_ACK_ID), + service_(ANY_SERVICE), + instance_(ANY_INSTANCE), + eventgroup_(0), + pending_id_(0) { +} + +service_t +unsubscribe_ack_command::get_service() const { + + return service_; +} + +void +unsubscribe_ack_command::set_service(service_t _service) { + + service_ = _service; +} + +instance_t +unsubscribe_ack_command::get_instance() const { + + return instance_; +} + +void +unsubscribe_ack_command::set_instance(instance_t _instance) { + + instance_ = _instance; +} + +eventgroup_t +unsubscribe_ack_command::get_eventgroup() const { + + return eventgroup_; +} + +void +unsubscribe_ack_command::set_eventgroup(eventgroup_t _eventgroup) { + + eventgroup_ = _eventgroup; +} + +pending_id_t +unsubscribe_ack_command::get_pending_id() const { + + return pending_id_; +} + +void +unsubscribe_ack_command::set_pending_id(pending_id_t _pending_id) { + + pending_id_ = _pending_id; +} + +void +unsubscribe_ack_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(pending_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &service_, sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&_buffer[its_offset], &instance_, sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&_buffer[its_offset], &eventgroup_, sizeof(eventgroup_)); + its_offset += sizeof(eventgroup_); + std::memcpy(&_buffer[its_offset], &pending_id_, sizeof(pending_id_)); +} + +void +unsubscribe_ack_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(pending_id_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&service_, &_buffer[its_offset], sizeof(service_)); + its_offset += sizeof(service_); + std::memcpy(&instance_, &_buffer[its_offset], sizeof(instance_)); + its_offset += sizeof(instance_); + std::memcpy(&eventgroup_, &_buffer[its_offset], sizeof(eventgroup_)); + its_offset += sizeof(eventgroup_); + std::memcpy(&pending_id_, &_buffer[its_offset], sizeof(pending_id_)); + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_command.cpp new file mode 100644 index 00000000000..247b301cc9f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/unsubscribe_command.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include <vsomeip/constants.hpp> + +#include "../include/unsubscribe_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +unsubscribe_command::unsubscribe_command() + : subscribe_command_base(id_e::UNSUBSCRIBE_ID) { +} + +void +unsubscribe_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // payload + subscribe_command_base::serialize(_buffer, _error); +} + +void +unsubscribe_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + size_t its_size(COMMAND_HEADER_SIZE + + sizeof(service_) + sizeof(instance_) + + sizeof(eventgroup_) + sizeof(major_) + + sizeof(event_) + sizeof(pending_id_)); + + if (its_size > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + subscribe_command_base::deserialize(_buffer, _error); +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_credentials_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_credentials_command.cpp new file mode 100644 index 00000000000..269c6a255a1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_credentials_command.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/update_security_credentials_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +update_security_credentials_command::update_security_credentials_command() + : command(id_e::UPDATE_SECURITY_CREDENTIALS_ID) { +} + +void +update_security_credentials_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + size_t its_size(COMMAND_HEADER_SIZE + + (credentials_.size() * (sizeof(uid_t) + sizeof(gid_t)))); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + for (const auto &c : credentials_) { + std::memcpy(&_buffer[its_offset], &c.first, sizeof(c.first)); + its_offset += sizeof(c.first); + std::memcpy(&_buffer[its_offset], &c.second, sizeof(c.second)); + its_offset += sizeof(c.second); + } +} + +void +update_security_credentials_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + if (COMMAND_HEADER_SIZE + size_ > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + size_t its_count(size_ / (sizeof(uid_t) + sizeof(gid_t))); + size_t its_offset(COMMAND_HEADER_SIZE); + + uid_t its_uid; + gid_t its_gid; + for (size_t i = 0; i < its_count; i++) { + std::memcpy(&its_uid, &_buffer[its_offset], sizeof(its_uid)); + its_offset += sizeof(its_uid); + std::memcpy(&its_gid, &_buffer[its_offset], sizeof(its_gid)); + its_offset += sizeof(its_gid); + + credentials_.emplace(std::make_pair(its_uid, its_gid)); + } +} + + +std::set<std::pair<uid_t, gid_t> > +update_security_credentials_command::get_credentials() const { + + return credentials_; +} + +void +update_security_credentials_command::set_credentials( + const std::set<std::pair<uid_t, gid_t> > &_credentials) { + + credentials_ = _credentials; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_command.cpp new file mode 100644 index 00000000000..7f5a144d0a8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_command.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <limits> + +#include "../include/update_security_policy_command.hpp" +#include "../../security/include/policy.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +update_security_policy_command::update_security_policy_command( + bool _is_internal) + : command(_is_internal ? + id_e::UPDATE_SECURITY_POLICY_INT_ID : + id_e::UPDATE_SECURITY_POLICY_ID) { +} + +void +update_security_policy_command::serialize(std::vector<byte_t> &_buffer, + error_e &_error) const { + + std::vector<byte_t> its_policy_data; + if (policy_) { + if (policy_->serialize(its_policy_data)) { + _error = error_e::ERROR_UNKNOWN; + return; + } + } + + size_t its_size(COMMAND_HEADER_SIZE + sizeof(update_id_) + + its_policy_data.size()); + + if (its_size > std::numeric_limits<command_size_t>::max()) { + + _error = error_e::ERROR_MAX_COMMAND_SIZE_EXCEEDED; + return; + } + + // resize buffer + _buffer.resize(its_size); + + // set size + size_ = static_cast<command_size_t>(its_size - COMMAND_HEADER_SIZE); + + // serialize header + command::serialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // serialize payload + size_t its_offset(COMMAND_HEADER_SIZE); + std::memcpy(&_buffer[its_offset], &update_id_, sizeof(update_id_)); + its_offset += sizeof(update_id_); + std::memcpy(&_buffer[its_offset], + &its_policy_data[0], its_policy_data.size()); +} + +void +update_security_policy_command::deserialize(const std::vector<byte_t> &_buffer, + error_e &_error) { + + if (COMMAND_HEADER_SIZE + sizeof(update_id_) > _buffer.size()) { + + _error = error_e::ERROR_NOT_ENOUGH_BYTES; + return; + } + + // deserialize header + command::deserialize(_buffer, _error); + if (_error != error_e::ERROR_OK) + return; + + // deserialize payload + std::memcpy(&update_id_, &_buffer[COMMAND_POSITION_PAYLOAD], + sizeof(update_id_)); + policy_ = std::make_shared<policy>(); + const byte_t *its_policy_data + = &_buffer[COMMAND_HEADER_SIZE + sizeof(update_id_)]; + uint32_t its_policy_size + = uint32_t(_buffer.size() - COMMAND_HEADER_SIZE - sizeof(update_id_)); + + if (its_policy_size == 0 + || !policy_->deserialize(its_policy_data, its_policy_size)) { + + _error = error_e::ERROR_UNKNOWN; + policy_.reset(); + return; + } +} + +uint32_t +update_security_policy_command::get_update_id() const { + + return update_id_; +} + +void +update_security_policy_command::set_update_id(uint32_t _update_id) { + + update_id_ = _update_id; +} + +std::shared_ptr<policy> +update_security_policy_command::get_policy() const { + + return policy_; +} + +void +update_security_policy_command::set_policy( + const std::shared_ptr<policy> &_policy) { + + policy_ = _policy; +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_response_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_response_command.cpp new file mode 100644 index 00000000000..91573f0a7fb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/protocol/src/update_security_policy_response_command.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/update_security_policy_response_command.hpp" + +namespace vsomeip_v3 { +namespace protocol { + +update_security_policy_response_command::update_security_policy_response_command() + : security_policy_response_command_base( + id_e::UPDATE_SECURITY_POLICY_RESPONSE_ID) { + +} + +} // namespace protocol +} // namespace vsomeip diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/event.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/event.hpp new file mode 100644 index 00000000000..447aff84a22 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/event.hpp @@ -0,0 +1,194 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_EVENT_IMPL_HPP_ +#define VSOMEIP_V3_EVENT_IMPL_HPP_ + +#include <list> +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <atomic> + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/function_types.hpp> +#include <vsomeip/payload.hpp> + + +namespace vsomeip_v3 { + + +class endpoint; +class endpoint_definition; +class message; +class payload; +class routing_manager; + +struct debounce_filter_impl_t; + +class event + : public std::enable_shared_from_this<event> { +public: + event(routing_manager *_routing, bool _is_shadow = false); + + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + major_version_t get_version() const; + void set_version(major_version_t _major); + + event_t get_event() const; + void set_event(event_t _event); + + std::shared_ptr<payload> get_payload() const; + + void set_payload(const std::shared_ptr<payload> &_payload, + const client_t _client, bool _force); + + void set_payload(const std::shared_ptr<payload> &_payload, + const client_t _client, + const std::shared_ptr<endpoint_definition>& _target, bool _force); + + bool prepare_update_payload(const std::shared_ptr<payload> &_payload, + bool _force); + void update_payload(); + + bool set_payload_notify_pending(const std::shared_ptr<payload> &_payload); + + void set_payload(const std::shared_ptr<payload> &_payload, bool _force); + void unset_payload(bool _force = false); + + event_type_e get_type() const; + void set_type(const event_type_e _type); + + reliability_type_e get_reliability() const; + void set_reliability(const reliability_type_e _reliability); + + bool is_field() const; + bool is_provided() const; + void set_provided(bool _is_provided); + + bool is_set() const; + + // SIP_RPC_357 + void set_update_cycle(std::chrono::milliseconds &_cycle); + void set_change_resets_cycle(bool _change_resets_cycle); + + // SIP_RPC_358 + void set_update_on_change(bool _is_active); + + // SIP_RPC_359 (epsilon change) + void set_epsilon_change_function( + const epsilon_change_func_t &_epsilon_change_func); + + std::set<eventgroup_t> get_eventgroups() const; + std::set<eventgroup_t> get_eventgroups(client_t _client) const; + void add_eventgroup(eventgroup_t _eventgroup); + void set_eventgroups(const std::set<eventgroup_t> &_eventgroups); + + void notify_one(client_t _client, + const std::shared_ptr<endpoint_definition> &_target); + void notify_one(client_t _client, bool _force); + + + bool add_subscriber(eventgroup_t _eventgroup, + const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client, bool _force); + void remove_subscriber(eventgroup_t _eventgroup, client_t _client); + bool has_subscriber(eventgroup_t _eventgroup, client_t _client); + std::set<client_t> get_subscribers(); + std::set<client_t> get_filtered_subscribers(bool _force); + std::set<client_t> update_and_get_filtered_subscribers( + const std::shared_ptr<payload> &_payload, bool _force); + VSOMEIP_EXPORT std::set<client_t> get_subscribers(eventgroup_t _eventgroup); + void clear_subscribers(); + + void add_ref(client_t _client, bool _is_provided); + void remove_ref(client_t _client, bool _is_provided); + bool has_ref(); + bool has_ref(client_t _client, bool _is_provided); + + bool is_shadow() const; + void set_shadow(bool _shadow); + + bool is_cache_placeholder() const; + void set_cache_placeholder(bool _is_cache_place_holder); + + bool is_subscribed(client_t _client); + + void remove_pending(const std::shared_ptr<endpoint_definition> &_target); + + void set_session(); + +private: + void update_cbk(boost::system::error_code const &_error); + void notify(bool _force); + void notify(client_t _client, + const std::shared_ptr<endpoint_definition> &_target); + + void start_cycle(); + void stop_cycle(); + + bool has_changed(const std::shared_ptr<payload> &_lhs, + const std::shared_ptr<payload> &_rhs) const; + + void notify_one_unlocked(client_t _client, bool _force); + void notify_one_unlocked(client_t _client, + const std::shared_ptr<endpoint_definition> &_target); + + bool prepare_update_payload_unlocked( + const std::shared_ptr<payload> &_payload, bool _force); + void update_payload_unlocked(); + + void get_pending_updates(const std::set<client_t> &_clients); + +private: + routing_manager *routing_; + mutable std::mutex mutex_; + + std::shared_ptr<message> current_; + std::shared_ptr<message> update_; + + std::atomic<event_type_e> type_; + + boost::asio::steady_timer cycle_timer_; + std::chrono::milliseconds cycle_; + + std::atomic<bool> change_resets_cycle_; + std::atomic<bool> is_updating_on_change_; + + mutable std::mutex eventgroups_mutex_; + std::map<eventgroup_t, std::set<client_t> > eventgroups_; + + std::atomic<bool> is_set_; + std::atomic<bool> is_provided_; + + std::mutex refs_mutex_; + std::map<client_t, std::map<bool, uint32_t>> refs_; + + std::atomic<bool> is_shadow_; + std::atomic<bool> is_cache_placeholder_; + + epsilon_change_func_t epsilon_change_func_; + bool has_default_epsilon_change_func_; + + std::atomic<reliability_type_e> reliability_; + + std::set<std::shared_ptr<endpoint_definition> > pending_; + + std::mutex filters_mutex_; + std::map<client_t, epsilon_change_func_t> filters_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_EVENT_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/eventgroupinfo.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/eventgroupinfo.hpp new file mode 100644 index 00000000000..2dc8279fc10 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/eventgroupinfo.hpp @@ -0,0 +1,155 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_EVENTGROUPINFO_HPP_ +#define VSOMEIP_V3_EVENTGROUPINFO_HPP_ + +#include <atomic> +#include <chrono> +#include <list> +#include <memory> +#include <mutex> +#include <set> +#include <vector> + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +#include "remote_subscription.hpp" +#include "types.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +class endpoint_definition; +class event; + +class eventgroupinfo { +public: + struct subscription_t { + std::shared_ptr<remote_subscription> subscription_; + std::chrono::steady_clock::time_point expiration_; + + bool operator==(const subscription_t &_other) const { + return (subscription_ == _other.subscription_); + } + }; + + VSOMEIP_EXPORT eventgroupinfo(); + VSOMEIP_EXPORT eventgroupinfo( + const service_t _service, const service_t _instance, + const eventgroup_t _eventgroup, const major_version_t _major, + const ttl_t _ttl, const uint8_t _max_remote_subscribers); + VSOMEIP_EXPORT ~eventgroupinfo(); + + VSOMEIP_EXPORT service_t get_service() const; + VSOMEIP_EXPORT void set_service(const service_t _service); + + VSOMEIP_EXPORT instance_t get_instance() const; + VSOMEIP_EXPORT void set_instance(const instance_t _instance); + + VSOMEIP_EXPORT eventgroup_t get_eventgroup() const; + VSOMEIP_EXPORT void set_eventgroup(const eventgroup_t _eventgroup); + + VSOMEIP_EXPORT major_version_t get_major() const; + VSOMEIP_EXPORT void set_major(const major_version_t _major); + + VSOMEIP_EXPORT ttl_t get_ttl() const; + VSOMEIP_EXPORT void set_ttl(const ttl_t _ttl); + + VSOMEIP_EXPORT bool is_multicast() const; + VSOMEIP_EXPORT bool get_multicast(boost::asio::ip::address &_address, + uint16_t &_port) const; + VSOMEIP_EXPORT void set_multicast(const boost::asio::ip::address &_address, + uint16_t _port); + VSOMEIP_EXPORT bool is_sending_multicast() const; + + VSOMEIP_EXPORT std::set<std::shared_ptr<event> > get_events() const; + VSOMEIP_EXPORT void add_event(const std::shared_ptr<event>& _event); + VSOMEIP_EXPORT void remove_event(const std::shared_ptr<event>& _event); + VSOMEIP_EXPORT reliability_type_e get_reliability() const; + VSOMEIP_EXPORT void set_reliability(reliability_type_e _reliability); + VSOMEIP_EXPORT bool is_reliability_auto_mode() const; + + VSOMEIP_EXPORT std::set<std::shared_ptr<remote_subscription>> + get_remote_subscriptions() const; + + std::shared_ptr<remote_subscription> get_remote_subscription( + const remote_subscription_id_t _id); + + bool update_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription, + const std::chrono::steady_clock::time_point &_expiration, + std::set<client_t> &_changed, remote_subscription_id_t &_id, + const bool _is_subscribe); + + bool is_remote_subscription_limit_reached( + const std::shared_ptr<remote_subscription> &_subscription); + + remote_subscription_id_t add_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription); + + VSOMEIP_EXPORT void remove_remote_subscription( + const remote_subscription_id_t _id); + + void clear_remote_subscriptions(); + + VSOMEIP_EXPORT std::set<std::shared_ptr<endpoint_definition> > + get_unicast_targets() const; + VSOMEIP_EXPORT std::set<std::shared_ptr<endpoint_definition> > + get_multicast_targets() const; + + VSOMEIP_EXPORT uint8_t get_threshold() const; + VSOMEIP_EXPORT void set_threshold(uint8_t _threshold); + + VSOMEIP_EXPORT bool is_selective() const; + + VSOMEIP_EXPORT void send_initial_events( + const std::shared_ptr<endpoint_definition> &_reliable, + const std::shared_ptr<endpoint_definition> &_unreliable) const; + + VSOMEIP_EXPORT uint8_t get_max_remote_subscribers() const; + VSOMEIP_EXPORT void set_max_remote_subscribers(uint8_t _max_remote_subscribers); + +private: + void update_id(); + uint32_t get_unreliable_target_count() const; + + std::atomic<service_t> service_; + std::atomic<instance_t> instance_; + std::atomic<eventgroup_t> eventgroup_; + std::atomic<major_version_t> major_; + std::atomic<ttl_t> ttl_; + + mutable std::mutex address_mutex_; + boost::asio::ip::address address_; + uint16_t port_; + + mutable std::mutex events_mutex_; + std::set<std::shared_ptr<event> > events_; + + std::atomic<uint8_t> threshold_; + + mutable std::mutex subscriptions_mutex_; + std::map<remote_subscription_id_t, + std::shared_ptr<remote_subscription> + > subscriptions_; + remote_subscription_id_t id_; + std::map<boost::asio::ip::address, uint8_t> remote_subscribers_count_; + + std::atomic<reliability_type_e> reliability_; + std::atomic<bool> reliability_auto_mode_; + + uint8_t max_remote_subscribers_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_EVENTGROUPINFO_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/function_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/function_types.hpp new file mode 100644 index 00000000000..2b22819307f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/function_types.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_FUNCTION_TYPES_HPP_ +#define VSOMEIP_V3_ROUTING_FUNCTION_TYPES_HPP_ + +namespace vsomeip_v3 { + +class remote_subscription; + +typedef std::function< + void (const std::shared_ptr<remote_subscription> &_subscription) +> remote_subscription_callback_t; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_FUNCTION_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/remote_subscription.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/remote_subscription.hpp new file mode 100644 index 00000000000..a770a56f7fb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/remote_subscription.hpp @@ -0,0 +1,153 @@ +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_REMOTE_SUBSCRIPTION_HPP_ +#define VSOMEIP_V3_REMOTE_SUBSCRIPTION_HPP_ + +#include <atomic> +#include <map> +#include <mutex> +#include <set> + +#include <vsomeip/primitive_types.hpp> + +#include "../../endpoints/include/endpoint_definition.hpp" +#include "types.hpp" +#include <vsomeip/export.hpp> + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +class eventgroupinfo; + +const remote_subscription_id_t PENDING_SUBSCRIPTION_ID(0); + +class remote_subscription { +public: + VSOMEIP_EXPORT remote_subscription(); + VSOMEIP_EXPORT ~remote_subscription(); + + bool operator==(const remote_subscription &_other) const; + bool equals(const std::shared_ptr<remote_subscription> &_other) const; + bool address_equals(const std::shared_ptr<remote_subscription> &_other) const; + + VSOMEIP_EXPORT void reset(const std::set<client_t> &_clients); + + VSOMEIP_EXPORT bool is_initial() const; + VSOMEIP_EXPORT void set_initial(const bool _is_initial); + + VSOMEIP_EXPORT bool force_initial_events() const; + VSOMEIP_EXPORT void set_force_initial_events(const bool _force_initial_events); + + remote_subscription_id_t get_id() const; + void set_id(const remote_subscription_id_t _id); + + VSOMEIP_EXPORT std::shared_ptr<remote_subscription> get_parent() const; + void set_parent(const std::shared_ptr<remote_subscription> &_parent); + + VSOMEIP_EXPORT std::shared_ptr<eventgroupinfo> get_eventgroupinfo() const; + VSOMEIP_EXPORT void set_eventgroupinfo(const std::shared_ptr<eventgroupinfo> &_info); + + VSOMEIP_EXPORT ttl_t get_ttl() const; + VSOMEIP_EXPORT void set_ttl(const ttl_t _ttl); + + uint16_t get_reserved() const; + void set_reserved(const uint16_t _reserved); + + uint8_t get_counter() const; + void set_counter(uint8_t _counter); + + VSOMEIP_EXPORT std::set<client_t> get_clients() const; + bool has_client() const; + bool has_client(const client_t _client) const; + void remove_client(const client_t _client); + + VSOMEIP_EXPORT remote_subscription_state_e get_client_state(const client_t _client) const; + void set_client_state(const client_t _client, + remote_subscription_state_e _state); + void set_all_client_states(remote_subscription_state_e _state); + + std::chrono::steady_clock::time_point get_expiration(const client_t _client) const; + + VSOMEIP_EXPORT std::shared_ptr<endpoint_definition> get_subscriber() const; + VSOMEIP_EXPORT void set_subscriber(const std::shared_ptr<endpoint_definition> &_subscriber); + + VSOMEIP_EXPORT std::shared_ptr<endpoint_definition> get_reliable() const; + VSOMEIP_EXPORT void set_reliable(const std::shared_ptr<endpoint_definition> &_reliable); + + VSOMEIP_EXPORT std::shared_ptr<endpoint_definition> get_unreliable() const; + VSOMEIP_EXPORT void set_unreliable(const std::shared_ptr<endpoint_definition> &_unreliable); + + VSOMEIP_EXPORT bool is_pending() const; + bool is_acknowledged() const; + + std::set<client_t> update(const std::set<client_t> &_clients, + const std::chrono::steady_clock::time_point &_timepoint, + const bool _is_subscribe); + + VSOMEIP_EXPORT std::uint32_t get_answers() const; + VSOMEIP_EXPORT void set_answers(const std::uint32_t _answers); + + VSOMEIP_EXPORT bool get_ip_address(boost::asio::ip::address &_address) const; + + bool is_expired() const; + void set_expired(); + bool is_forwarded() const; + void set_forwarded(); + +private: + std::atomic<remote_subscription_id_t> id_; + std::atomic<bool> is_initial_; + std::atomic<bool> force_initial_events_; + std::weak_ptr<remote_subscription> parent_; + + std::weak_ptr<eventgroupinfo> eventgroupinfo_; + + ttl_t ttl_; + std::uint16_t reserved_; + std::uint8_t counter_; + + std::map<client_t, + std::pair<remote_subscription_state_e, + std::chrono::steady_clock::time_point + > + > clients_; + + // The endpoint that sent(!) the subscription + std::shared_ptr<endpoint_definition> subscriber_; + + // The endpoints defined by the endpoint options + std::shared_ptr<endpoint_definition> reliable_; + std::shared_ptr<endpoint_definition> unreliable_; + + // Number of acknowledgements that must be sent + // for the subscriptions. This is usally 1, but + // may be larger if a matching subscription arrived + // before the subscription could be acknowledged + std::atomic<std::uint32_t> answers_; + + mutable std::mutex mutex_; + + /* + * This flag specifies what the "winner" of the + * expire_subscriptions()/on_remote_subscribe() + * race shall have as destination: + * - expiration, if expire_subscriptions() runs first + * - forwarding, if on_remote_subscribe() runs first + */ + enum struct destiny : std::uint8_t { + none, + expire, + forward + }; + std::atomic<destiny> final_destination_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_REMOTE_SUBSCRIPTION_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_host.hpp new file mode 100644 index 00000000000..2203bed8b59 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_host.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_HOST_ +#define VSOMEIP_V3_ROUTING_HOST_ + +#include <memory> + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/vsomeip_sec.h> + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +namespace vsomeip_v3 { + +class endpoint; + +class routing_host { +public: + virtual ~routing_host() = default; + + virtual void on_message(const byte_t *_data, length_t _length, + endpoint *_receiver, + bool _is_multicast = false, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + const vsomeip_sec_client_t *_sec_client = nullptr, + const boost::asio::ip::address &_remote_address = + boost::asio::ip::address(), + std::uint16_t _remote_port = 0) = 0; + + virtual client_t get_client() const = 0; + virtual void add_known_client(client_t _client, const std::string &_client_host) = 0; + + virtual void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) = 0; + + virtual routing_state_e get_routing_state() = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_HOST_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager.hpp new file mode 100644 index 00000000000..58f38ca4b15 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager.hpp @@ -0,0 +1,140 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_ +#define VSOMEIP_V3_ROUTING_MANAGER_ + +#include <memory> +#include <set> +#include <vector> + +#include <boost/asio/io_context.hpp> +#include <vsomeip/function_types.hpp> +#include <vsomeip/structured_types.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/handler.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "types.hpp" + +#include "../../configuration/include/debounce_filter_impl.hpp" +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +namespace vsomeip_v3 { + +class endpoint; +class endpoint_definition; +class event; +class payload; +class security; + +class routing_manager { +public: + virtual ~routing_manager() { + } + + virtual boost::asio::io_context &get_io() = 0; + virtual client_t get_client() const = 0; +// virtual void set_client(const client_t &_client) = 0; + virtual session_t get_session(bool _is_request) = 0; + + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; + + virtual void init() = 0; + virtual void start() = 0; + virtual void stop() = 0; + + virtual bool offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; + + virtual void stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; + + virtual void request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; + + virtual void release_service(client_t _client, service_t _service, + instance_t _instance) = 0; + + virtual void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) = 0; + + virtual void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) = 0; + + virtual bool send(client_t _client, std::shared_ptr<message> _message, + bool _force) = 0; + + virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client = VSOMEIP_ROUTING_CLIENT, + const vsomeip_sec_client_t *_sec_client = nullptr, + uint8_t _status_check = 0, + bool _sent_from_remote = false, + bool _force = true) = 0; + + virtual bool send_to(const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message) = 0; + + virtual bool send_to(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, instance_t _instance) = 0; + + virtual void register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow = false, + bool _is_cache_placeholder = false) = 0; + + virtual void unregister_event(client_t _client, service_t _service, + instance_t _instance, event_t _event, bool _is_provided) = 0; + + virtual std::shared_ptr<event> find_event(service_t _service, + instance_t _instance, event_t _event) const = 0; + + virtual std::set<std::shared_ptr<event>> find_events(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const = 0; + + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force) = 0; + + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force +#ifdef VSOMEIP_ENABLE_COMPAT + , bool _remote_subscriber +#endif + ) = 0; + + virtual void set_routing_state(routing_state_e _routing_state) = 0; + + virtual void send_get_offered_services_info(client_t _client, offer_type_e _offer_type) = 0; + + virtual void debounce_timeout_update_cbk(const boost::system::error_code &_error, const std::shared_ptr<vsomeip_v3::event> &_event, client_t _client, const std::shared_ptr<debounce_filter_impl_t> &_filter) = 0; + virtual void register_debounce(const std::shared_ptr<debounce_filter_impl_t> &_filter, client_t _client, const std::shared_ptr<vsomeip_v3::event> &_event) = 0; + virtual void remove_debounce(client_t _client, event_t _event) = 0; + virtual void update_debounce_clients(const std::set<client_t> &_clients, event_t _event) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_adapter.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_adapter.hpp new file mode 100644 index 00000000000..26154b0920d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_adapter.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_ADAPTER_ +#define VSOMEIP_V3_ROUTING_MANAGER_ADAPTER_ + +namespace vsomeip_v3 { + +class routing_manager; + +class routing_manager_adapter { +public: + virtual ~routing_manager_adapter() { + } + + virtual routing_manager * get_manager() = 0; + virtual void process_command(const byte_t *_data, length_t _length) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_ADAPTER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_base.hpp new file mode 100644 index 00000000000..51262e5ff9e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_base.hpp @@ -0,0 +1,389 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_BASE_ +#define VSOMEIP_V3_ROUTING_MANAGER_BASE_ + +#include <mutex> +#include <unordered_set> +#include <queue> +#include <condition_variable> + +#include <vsomeip/constants.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "types.hpp" +#include "event.hpp" +#include "serviceinfo.hpp" +#include "routing_host.hpp" +#include "eventgroupinfo.hpp" +#include "routing_manager.hpp" +#include "routing_manager_host.hpp" + +#include "../../message/include/serializer.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint_manager_base.hpp" + +#if defined(__QNX__) +#include "../../utility/include/qnx_helper.hpp" +#endif + +namespace vsomeip_v3 { + +#ifdef USE_DLT +namespace trace { +class connector_impl; +} // namespace trace +#endif + +class serializer; + +class routing_manager_base : public routing_manager, + public routing_host, + public std::enable_shared_from_this<routing_manager_base> { + +public: + routing_manager_base(routing_manager_host *_host); + virtual ~routing_manager_base() = default; + + virtual boost::asio::io_context &get_io(); + virtual client_t get_client() const; + + virtual std::string get_client_host() const; + virtual void set_client_host(const std::string &_client_host); + virtual void set_client(const client_t &_client); + virtual session_t get_session(bool _is_request); + + virtual const vsomeip_sec_client_t *get_sec_client() const; + virtual void set_sec_client_port(port_t _port); + + virtual std::string get_env(client_t _client) const = 0; + + virtual void debounce_timeout_update_cbk(const boost::system::error_code &_error, const std::shared_ptr<vsomeip_v3::event> &_event, client_t _client, const std::shared_ptr<debounce_filter_impl_t> &_filter); + virtual void register_debounce(const std::shared_ptr<debounce_filter_impl_t> &_filter, client_t _client, const std::shared_ptr<vsomeip_v3::event> &_event); + virtual void remove_debounce(client_t _client, event_t _event); + virtual void update_debounce_clients(const std::set<client_t> &_clients, event_t _event); + + virtual bool is_routing_manager() const; + + virtual void init() = 0; + void init(const std::shared_ptr<endpoint_manager_base>& _endpoint_manager); + + virtual bool offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + virtual void stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + virtual void request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + virtual void release_service(client_t _client, + service_t _service, instance_t _instance); + + virtual void register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow = false, + bool _is_cache_placeholder = false); + + virtual void unregister_event(client_t _client, + service_t _service, instance_t _instance, event_t _event, + bool _is_provided); + + virtual std::set<std::shared_ptr<event>> find_events(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + + virtual void subscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter); + + virtual void unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, bool _force); + + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force +#ifdef VSOMEIP_ENABLE_COMPAT + , bool _remote_subscriber +#endif + ); + + virtual bool send(client_t _client, std::shared_ptr<message> _message, + bool _force); + + virtual bool send(client_t _client, const byte_t *_data, uint32_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force) = 0; + + // routing host -> will be implemented by routing_manager_impl/_proxy/ + virtual void on_message(const byte_t *_data, length_t _length, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port = 0) = 0; + + virtual void set_routing_state(routing_state_e _routing_state) = 0; + + virtual routing_state_e get_routing_state(); + + virtual void register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint) = 0; + + virtual void send_get_offered_services_info(client_t _client, offer_type_e _offer_type) = 0; + + std::set<client_t> find_local_clients(service_t _service, instance_t _instance); + + std::shared_ptr<serviceinfo> find_service(service_t _service, instance_t _instance) const; + + client_t find_local_client(service_t _service, instance_t _instance) const; + client_t find_local_client_unlocked(service_t _service, instance_t _instance) const; + + std::shared_ptr<event> find_event(service_t _service, instance_t _instance, + event_t _event) const; + + // address data for vsomeip routing via TCP + bool get_guest(client_t _client, boost::asio::ip::address &_address, + port_t &_port) const; + void add_guest(client_t _client, const boost::asio::ip::address &_address, + port_t _port); + void remove_guest(client_t _client); + + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); + + virtual void on_connect(const std::shared_ptr<endpoint>& _endpoint) = 0; + virtual void on_disconnect(const std::shared_ptr<endpoint>& _endpoint) = 0; +protected: + std::shared_ptr<serviceinfo> create_service_info(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, bool _is_local_service); + + void clear_service_info(service_t _service, instance_t _instance, bool _reliable); + services_t get_services() const; + services_t get_services_remote() const; + bool is_available(service_t _service, instance_t _instance, major_version_t _major); + + void remove_local(client_t _client, bool _remove_sec_client); + void remove_local(client_t _client, + const std::set< + std::tuple<service_t, instance_t, eventgroup_t> + > &_subscribed_eventgroups, + bool _remove_sec_client); + + std::set<std::shared_ptr<eventgroupinfo> > find_eventgroups(service_t _service, + instance_t _instance) const; + + std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + + void remove_eventgroup_info(service_t _service, instance_t _instance, + eventgroup_t _eventgroup); + + bool send_local_notification(client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _reliable, uint8_t _status_check, bool _force); + + bool send_local( + std::shared_ptr<endpoint> &_target, client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _reliable, protocol::id_e _command, uint8_t _status_check) const; + + bool insert_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + const std::shared_ptr<debounce_filter_impl_t> &_filter, client_t _client, + std::set<event_t> *_already_subscribed_events); + + void clear_shadow_subscriptions(void); + + std::shared_ptr<serializer> get_serializer(); + void put_serializer(const std::shared_ptr<serializer> &_serializer); + std::shared_ptr<deserializer> get_deserializer(); + void put_deserializer(const std::shared_ptr<deserializer> &_deserializer); + + void send_pending_subscriptions(service_t _service, + instance_t _instance, major_version_t _major); + + virtual void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) = 0; + + void remove_pending_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); +#ifdef VSOMEIP_ENABLE_COMPAT + void send_pending_notify_ones(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client, bool _remote_subscriber = false); +#endif + + void unset_all_eventpayloads(service_t _service, instance_t _instance); + void unset_all_eventpayloads(service_t _service, instance_t _instance, + eventgroup_t _eventgroup); + + void notify_one_current_value(client_t _client, service_t _service, + instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + const std::set<event_t> &_events_to_exclude); + + std::set<std::tuple<service_t, instance_t, eventgroup_t>> + get_subscriptions(const client_t _client); + + std::vector<event_t> find_events(service_t _service, instance_t _instance) const; + + bool is_response_allowed(client_t _sender, service_t _service, + instance_t _instance, method_t _method); + bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup); + + void add_known_client(client_t _client, const std::string &_client_host); + +#ifdef VSOMEIP_ENABLE_COMPAT + void set_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, subscription_state_e _state); + + subscription_state_e get_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + void erase_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); +#endif + +private: + virtual bool create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client) = 0; + +protected: + routing_manager_host *host_; + boost::asio::io_context &io_; + + std::shared_ptr<configuration> configuration_; + + std::queue<std::shared_ptr<serializer>> serializers_; + std::mutex serializer_mutex_; + std::condition_variable serializer_condition_; + + std::queue<std::shared_ptr<deserializer>> deserializers_; + std::mutex deserializer_mutex_; + std::condition_variable deserializer_condition_; + + mutable std::mutex local_services_mutex_; + typedef std::map<service_t, std::map<instance_t, + std::tuple<major_version_t, minor_version_t, client_t>>> local_services_map_t; + local_services_map_t local_services_; + std::map<service_t, std::map<instance_t, std::set<client_t> > > local_services_history_; + + // Eventgroups + mutable std::mutex eventgroups_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_; + // Events (part of one or more eventgroups) + mutable std::mutex events_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<event_t, + std::shared_ptr<event> > > > events_; + + boost::asio::steady_timer debounce_timer; + std::multimap<std::chrono::steady_clock::time_point, std::tuple<client_t, bool, std::function<void (const boost::system::error_code)>, event_t>> debounce_clients_; + mutable std::mutex debounce_mutex_; + + std::mutex event_registration_mutex_; + + struct subscription_data_t { + service_t service_; + instance_t instance_; + eventgroup_t eventgroup_; + major_version_t major_; + event_t event_; + std::shared_ptr<debounce_filter_impl_t> filter_; + vsomeip_sec_client_t sec_client_; + + bool operator<(const subscription_data_t &_other) const { + return (service_ < _other.service_ + || (service_ == _other.service_ + && instance_ < _other.instance_) + || (service_ == _other.service_ + && instance_ == _other.instance_ + && eventgroup_ < _other.eventgroup_) + || (service_ == _other.service_ + && instance_ == _other.instance_ + && eventgroup_ == _other.eventgroup_ + && event_ < _other.event_)); + } + }; + std::set<subscription_data_t> pending_subscriptions_; + + services_t services_remote_; + mutable std::mutex services_remote_mutex_; + + std::shared_ptr<endpoint_manager_base> ep_mgr_; + + mutable std::mutex known_clients_mutex_; + std::map<client_t, std::string> known_clients_; + + mutable std::mutex env_mutex_; + std::string env_; + + std::mutex routing_state_mutex_; + routing_state_e routing_state_; + +#ifdef USE_DLT + std::shared_ptr<trace::connector_impl> tc_; +#endif + +private: + services_t services_; + mutable std::mutex services_mutex_; + + mutable std::mutex guests_mutex_; + std::map<client_t, + std::pair<boost::asio::ip::address, port_t> + > guests_; + + std::mutex add_known_client_mutex_; + +#ifdef VSOMEIP_ENABLE_COMPAT + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<message> > > > pending_notify_ones_; + std::recursive_mutex pending_notify_ones_mutex_; + std::map<client_t, + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::map<event_t, + subscription_state_e> > > > > incoming_subscription_state_; + std::recursive_mutex incoming_subscription_state_mutex_; +#endif + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_BASE_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_client.hpp new file mode 100644 index 00000000000..4d6bbd1f85f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_client.hpp @@ -0,0 +1,298 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP +#define VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP + +#include <map> +#include <mutex> +#include <atomic> +#include <tuple> + +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/handler.hpp> + +#include "routing_manager_base.hpp" +#include "types.hpp" +#include "../../protocol/include/protocol.hpp" + +namespace vsomeip_v3 { + +class configuration; +class event; +#ifdef __linux__ +class netlink_connector; +#endif +class routing_manager_host; + +namespace protocol { + class offered_services_response_command; + class update_security_credentials_command; +} + +class routing_manager_client + : public routing_manager_base { +public: + routing_manager_client(routing_manager_host *_host, bool _client_side_logging, + const std::set<std::tuple<service_t, instance_t> > & _client_side_logging_filter); + virtual ~routing_manager_client(); + + void init(); + void start(); + void stop(); + + std::shared_ptr<configuration> get_configuration() const; + std::string get_env(client_t _client) const; + std::string get_env_unlocked(client_t _client) const; + + bool offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void release_service(client_t _client, + service_t _service, instance_t _instance); + + void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter); + + void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + bool send(client_t _client, const byte_t *_data, uint32_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force); + + bool send_to(const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message); + + bool send_to(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, instance_t _instance); + + void register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder); + + void unregister_event(client_t _client, service_t _service, + instance_t _instance, event_t _notifier, bool _is_provided); + + void on_connect(const std::shared_ptr<endpoint>& _endpoint); + void on_disconnect(const std::shared_ptr<endpoint>& _endpoint); + void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, + bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + + void on_routing_info(const byte_t *_data, uint32_t _size); + + void register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint); + void handle_client_error(client_t _client); + + void on_offered_services_info(protocol::offered_services_response_command &_command); + + void send_get_offered_services_info(client_t _client, offer_type_e _offer_type); + +private: + void assign_client(); + void register_application(); + void deregister_application(); + + void reconnect(const std::map<client_t, std::string> &_clients); + + void send_pong() const; + + void send_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + + void send_release_service(client_t _client, + service_t _service, instance_t _instance); + + void send_pending_event_registrations(client_t _client); + + void send_register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, reliability_type_e _reliability, + bool _is_provided, bool _is_cyclic); + + void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter); + + void send_subscribe_nack(client_t _subscriber, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _id); + + void send_subscribe_ack(client_t _subscriber, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _id); + + bool is_field(service_t _service, instance_t _instance, + event_t _event) const; + + void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event); + + void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event); + + void cache_event_payload(const std::shared_ptr<message> &_message); + + void on_stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void send_pending_commands(); + + void init_receiver(); + + void notify_remote_initially(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude); + + uint32_t get_remote_subscriber_count(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, bool _increment); + void clear_remote_subscriber_count(service_t _service, instance_t _instance); + + void assign_client_timeout_cbk(boost::system::error_code const &_error); + + void register_application_timeout_cbk(boost::system::error_code const &_error); + + void send_registered_ack(); + + void set_routing_state(routing_state_e _routing_state) { + (void)_routing_state; + }; + + bool is_client_known(client_t _client); + + bool create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _notifier, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client); + + void request_debounce_timeout_cbk(boost::system::error_code const &_error); + + void send_request_services(const std::set<protocol::service> &_requests); + + void send_unsubscribe_ack(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, remote_subscription_id_t _id); + + void resend_provided_event_registrations(); + void send_resend_provided_event_response(pending_remote_offer_id_t _id); + +#ifndef VSOMEIP_DISABLE_SECURITY + void send_update_security_policy_response(pending_security_update_id_t _update_id); + void send_remove_security_policy_response(pending_security_update_id_t _update_id); + void on_update_security_credentials(const protocol::update_security_credentials_command &_command); +#endif + void on_client_assign_ack(const client_t &_client); + + port_t get_routing_port(); + + void on_suspend(); + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + void on_net_state_change(bool _is_interface, const std::string &_name, bool _is_available); +#endif + +private: + + enum class inner_state_type_e : std::uint8_t { + ST_REGISTERED = 0x0, + ST_DEREGISTERED = 0x1, + ST_REGISTERING = 0x2, + ST_ASSIGNING = 0x3, + ST_ASSIGNED = 0x4 + }; + + std::atomic_bool is_connected_; + std::atomic_bool is_started_; + std::atomic<inner_state_type_e> state_; + + std::shared_ptr<endpoint> sender_; // --> stub + std::shared_ptr<endpoint> receiver_; // --> from everybody + + std::set<protocol::service> pending_offers_; + std::set<protocol::service> requests_; + std::set<protocol::service> requests_to_debounce_; + + struct event_data_t { + service_t service_; + instance_t instance_; + event_t notifier_; + event_type_e type_; + reliability_type_e reliability_; + bool is_provided_; + bool is_cyclic_; + std::set<eventgroup_t> eventgroups_; + + bool operator<(const event_data_t &_other) const { + return std::tie(service_, instance_, notifier_, + type_, reliability_, is_provided_, is_cyclic_, eventgroups_) + < std::tie(_other.service_, _other.instance_, + _other.notifier_, _other.type_, _other.reliability_, + _other.is_provided_, _other.is_cyclic_, _other.eventgroups_); + } + }; + std::set<event_data_t> pending_event_registrations_; + + std::map<client_t, std::set<subscription_data_t>> pending_incoming_subscriptions_; + std::recursive_mutex incoming_subscriptions_mutex_; + + std::mutex state_mutex_; + std::condition_variable state_condition_; + + std::map<service_t, + std::map<instance_t, std::map<eventgroup_t, uint32_t > > > remote_subscriber_count_; + std::mutex remote_subscriber_count_mutex_; + + mutable std::mutex sender_mutex_; + + boost::asio::steady_timer register_application_timer_; + + std::mutex request_timer_mutex_; + boost::asio::steady_timer request_debounce_timer_; + bool request_debounce_timer_running_; + + const bool client_side_logging_; + const std::set<std::tuple<service_t, instance_t> > client_side_logging_filter_; + + std::mutex stop_mutex_; + +#if defined(__linux__) || defined(ANDROID) + std::shared_ptr<netlink_connector> local_link_connector_; + bool is_local_link_available_; +#endif +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_host.hpp new file mode 100644 index 00000000000..ec9788b2dee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_host.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_HOST_ +#define VSOMEIP_V3_ROUTING_MANAGER_HOST_ + +#include <memory> + +#include <boost/asio/io_context.hpp> +#include <vsomeip/error.hpp> +#include <vsomeip/vsomeip_sec.h> + +namespace vsomeip_v3 { + +class configuration; +class message; + +class routing_manager_host { +public: + virtual ~routing_manager_host() { + } + + virtual client_t get_client() const = 0; + virtual void set_client(const client_t &_client) = 0; + virtual session_t get_session(bool _is_request) = 0; + + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; + virtual void set_sec_client_port(port_t _port) = 0; + + virtual const std::string & get_name() const = 0; + virtual std::shared_ptr<configuration> get_configuration() const = 0; + virtual boost::asio::io_context &get_io() = 0; + + virtual void on_availability(service_t _service, instance_t _instance, + availability_state_e _state, + major_version_t _major = DEFAULT_MAJOR, + minor_version_t _minor = DEFAULT_MINOR) = 0; + virtual void on_state(state_type_e _state) = 0; + virtual void on_message(std::shared_ptr<message> &&_message) = 0; + virtual void on_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + client_t _client, const vsomeip_sec_client_t *_sec_client, + const std::string &_env, bool _subscribed, + const std::function<void(bool)> &_accepted_cb) = 0; + virtual void on_subscription_status(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error) = 0; + virtual void send(std::shared_ptr<message> _message) = 0; + virtual void on_offered_services_info( + std::vector<std::pair<service_t, instance_t>> &_services) = 0; + virtual bool is_routing() const = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_HOST_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_impl.hpp new file mode 100644 index 00000000000..0a216ea09da --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_impl.hpp @@ -0,0 +1,567 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_IMPL_HPP_ +#define VSOMEIP_V3_ROUTING_MANAGER_IMPL_HPP_ + +#include <map> +#include <memory> +#include <mutex> +#include <vector> +#include <list> +#include <unordered_set> + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/handler.hpp> + +#include "routing_manager_base.hpp" +#include "routing_manager_stub_host.hpp" +#include "types.hpp" + +#include "../../endpoints/include/netlink_connector.hpp" +#include "../../service_discovery/include/service_discovery_host.hpp" +#include "../../endpoints/include/endpoint_manager_impl.hpp" + + +namespace vsomeip_v3 { + +class configuration; +class deserializer; +class eventgroupinfo; +class routing_manager_host; +class routing_manager_stub; +class serializer; +class service_endpoint; + +namespace sd { +class service_discovery; +} // namespace sd + +namespace e2e { +class e2e_provider; +} // namespace e2e + +class routing_manager_impl: public routing_manager_base, + public routing_manager_stub_host, + public sd::service_discovery_host { +public: + routing_manager_impl(routing_manager_host *_host); + ~routing_manager_impl(); + + boost::asio::io_context &get_io(); + client_t get_client() const; + const vsomeip_sec_client_t *get_sec_client() const; + std::string get_client_host() const; + void set_client_host(const std::string &_client_host); + + bool is_routing_manager() const; + + void init(); + void start(); + void stop(); + + bool offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void release_service(client_t _client, + service_t _service, instance_t _instance); + + void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter); + + void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + bool send(client_t _client, std::shared_ptr<message> _message, + bool _force); + + bool send(client_t _client, const byte_t *_data, uint32_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, + bool _force); + + bool send_to(const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message); + + bool send_to(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, + instance_t _instance); + + bool send_via_sd(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port); + + void register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder); + + void register_shadow_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + event_type_e _type, reliability_type_e _reliability, + bool _is_provided, bool _is_cyclic); + + void unregister_shadow_event(client_t _client, service_t _service, + instance_t _instance, event_t _event, + bool _is_provided); + + void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force +#ifdef VSOMEIP_ENABLE_COMPAT + , bool _remote_subscriber +#endif + ); + + void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _id); + + void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + bool _remove, remote_subscription_id_t _id); + + + // interface to stub + inline std::shared_ptr<endpoint> find_local(client_t _client) { + return ep_mgr_->find_local(_client); + } + inline std::shared_ptr<endpoint> find_or_create_local( + client_t _client) { + return ep_mgr_->find_or_create_local(_client); + } + + std::shared_ptr<endpoint> find_or_create_remote_client( + service_t _service, instance_t _instance, bool _reliable); + + void remove_local(client_t _client, bool _remove_uid); + void on_stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void on_availability(service_t _service, instance_t _instance, + availability_state_e _state, + major_version_t _major, minor_version_t _minor); + + void on_pong(client_t _client); + + void on_subscribe_ack_with_multicast( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port); + void on_unsubscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + remote_subscription_id_t _id); + + void on_connect(const std::shared_ptr<endpoint>& _endpoint); + void on_disconnect(const std::shared_ptr<endpoint>& _endpoint); + + void on_message(const byte_t *_data, length_t _size, endpoint *_receiver, + bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + bool on_message(service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _check_status = 0, + bool _is_from_remote = false); + void on_notification(client_t _client, service_t _service, + instance_t _instance, const byte_t *_data, length_t _size, + bool _notify_one); + + bool offer_service_remotely(service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + bool _magic_cookies_enabled); + bool stop_offer_service_remotely(service_t _service, instance_t _instance, + std::uint16_t _port, bool _reliable, + bool _magic_cookies_enabled); + + // interface "service_discovery_host" + std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const; + services_t get_offered_services() const; + std::shared_ptr<serviceinfo> get_offered_service( + service_t _service, instance_t _instance) const; + std::map<instance_t, std::shared_ptr<serviceinfo>> get_offered_service_instances( + service_t _service) const; + + std::shared_ptr<endpoint> create_service_discovery_endpoint(const std::string &_address, + uint16_t _port, bool _reliable); + void init_routing_info(); + void add_routing_info(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, ttl_t _ttl, + const boost::asio::ip::address &_reliable_address, + uint16_t _reliable_port, + const boost::asio::ip::address &_unreliable_address, + uint16_t _unreliable_port); + void del_routing_info(service_t _service, instance_t _instance, + bool _has_reliable, bool _has_unreliable); + void update_routing_info(std::chrono::milliseconds _elapsed); + + // Handle remote subscriptions / subscription acks + void on_remote_subscribe( + std::shared_ptr<remote_subscription> &_subscription, + const remote_subscription_callback_t& _callback); + void on_remote_unsubscribe( + std::shared_ptr<remote_subscription> &_subscription); + + void expire_subscriptions(const boost::asio::ip::address &_address); + void expire_subscriptions(const boost::asio::ip::address &_address, + std::uint16_t _port, bool _reliable); + void expire_subscriptions(const boost::asio::ip::address &_address, + const configuration::port_range_t& _range, + bool _reliable); + void expire_services(const boost::asio::ip::address &_address); + void expire_services(const boost::asio::ip::address &_address, + std::uint16_t _port , bool _reliable); + void expire_services(const boost::asio::ip::address &_address, + const configuration::port_range_t& _range , bool _reliable); + + std::chrono::steady_clock::time_point expire_subscriptions(bool _force); + + void register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint); + void handle_client_error(client_t _client); + std::shared_ptr<endpoint_manager_impl> get_endpoint_manager() const; + + routing_state_e get_routing_state(); + void set_routing_state(routing_state_e _routing_state); + + void send_get_offered_services_info(client_t _client, offer_type_e _offer_type) { + (void) _client; + (void) _offer_type; + } + + void send_initial_events(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + const std::shared_ptr<endpoint_definition> &_subscriber); + + void print_stub_status() const; + + void send_error(return_code_e _return_code, const byte_t *_data, + length_t _size, instance_t _instance, bool _reliable, + endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + void service_endpoint_connected(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + const std::shared_ptr<endpoint>& _endpoint, + bool _unreliable_only); + void service_endpoint_disconnected(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + const std::shared_ptr<endpoint>& _endpoint); + + void register_sd_acceptance_handler(const sd_acceptance_handler_t& _handler) const; + void register_reboot_notification_handler(const reboot_notification_handler_t& _handler) const; + void register_routing_ready_handler(const routing_ready_handler_t& _handler); + void register_routing_state_handler(const routing_state_handler_t& _handler); + void sd_acceptance_enabled(const boost::asio::ip::address& _address, + const configuration::port_range_t& _range, + bool _reliable); + + void on_resend_provided_events_response(pending_remote_offer_id_t _id); + client_t find_local_client(service_t _service, instance_t _instance); + std::set<client_t> find_local_clients(service_t _service, instance_t _instance); + bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup); + +#ifndef VSOMEIP_DISABLE_SECURITY + bool update_security_policy_configuration(uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy, + const std::shared_ptr<payload> &_payload, + const security_update_handler_t &_handler); + bool remove_security_policy_configuration(uid_t _uid, gid_t _gid, + const security_update_handler_t &_handler); +#endif + + void add_known_client(client_t _client, const std::string &_client_host); + + void register_message_acceptance_handler( + const message_acceptance_handler_t &_handler); + + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); + +private: + bool offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _must_queue); + + void stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _must_queue); + + bool deliver_message(const byte_t *_data, length_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check = 0, bool _is_from_remote = false); + bool deliver_notification(service_t _service, instance_t _instance, + const byte_t *_data, length_t _length, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check = 0, bool _is_from_remote = false); + + bool is_suppress_event(service_t _service, instance_t _instance, + event_t _event) const; + + void init_service_info(service_t _service, + instance_t _instance, bool _is_local_service); + + bool is_field(service_t _service, instance_t _instance, + event_t _event) const; + + std::shared_ptr<endpoint> find_remote_client(service_t _service, + instance_t _instance, bool _reliable, client_t _client); + + std::shared_ptr<endpoint> create_remote_client(service_t _service, + instance_t _instance, bool _reliable, client_t _client); + + void clear_client_endpoints(service_t _service, instance_t _instance, bool _reliable); + void clear_multicast_endpoints(service_t _service, instance_t _instance); + + std::set<eventgroup_t> get_subscribed_eventgroups(service_t _service, + instance_t _instance); + + void clear_targets_and_pending_sub_from_eventgroups(service_t _service, instance_t _instance); + void clear_remote_subscriber(service_t _service, instance_t _instance); + + return_code_e check_error(const byte_t *_data, length_t _size, + instance_t _instance); + + bool supports_selective(service_t _service, instance_t _instance); + + void clear_remote_subscriber(service_t _service, instance_t _instance, + client_t _client, + const std::shared_ptr<endpoint_definition> &_target); + + void log_version_timer_cbk(boost::system::error_code const & _error); + + bool handle_local_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major,minor_version_t _minor); + + void send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter); + + void on_net_interface_or_route_state_changed(bool _is_interface, + const std::string &_if, + bool _available); + + void start_ip_routing(); + + void add_requested_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + void remove_requested_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + std::vector<std::pair<service_t, instance_t>> get_requested_services(client_t _client); + std::set<client_t> get_requesters(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + std::set<client_t> get_requesters_unlocked(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + bool has_requester_unlocked(service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor); + + void call_sd_endpoint_connected(const boost::system::error_code &_error, + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint> &_endpoint, + std::shared_ptr<boost::asio::steady_timer> _timer); + + bool create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client); + + void handle_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + void memory_log_timer_cbk(boost::system::error_code const &_error); + void status_log_timer_cbk(boost::system::error_code const &_error); + + void send_subscription(const client_t _offering_client, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, const major_version_t _major, + const std::set<client_t> &_clients, + const remote_subscription_id_t _id); + + void send_unsubscription(client_t _offering_client, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, const major_version_t _major, + const std::set<client_t> &_removed, + const remote_subscription_id_t _id); + + void send_expired_subscription(client_t _offering_client, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, + const std::set<client_t> &_removed, + const remote_subscription_id_t _id); + + void cleanup_server_endpoint(service_t _service, + const std::shared_ptr<endpoint>& _endpoint); + + pending_remote_offer_id_t pending_remote_offer_add(service_t _service, + instance_t _instance); + std::pair<service_t, instance_t> pending_remote_offer_remove( + pending_remote_offer_id_t _id); + + bool insert_offer_command(service_t _service, instance_t _instance, uint8_t _command, + client_t _client, major_version_t _major, minor_version_t _minor); + bool erase_offer_command(service_t _service, instance_t _instance); + + std::string get_env(client_t _client) const; + std::string get_env_unlocked(client_t _client) const; + + bool insert_event_statistics(service_t _service, instance_t _instance, + method_t _method, length_t _length); + void statistics_log_timer_cbk(boost::system::error_code const & _error); + + bool get_guest(client_t _client, boost::asio::ip::address &_address, + port_t &_port) const; + void add_guest(client_t _client, const boost::asio::ip::address &_address, + port_t _port); + void remove_guest(client_t _client); + + void send_suspend() const; + + void clear_local_services(); + + bool is_acl_message_allowed(endpoint *_receiver, + service_t _service, instance_t _instance, + const boost::asio::ip::address &_remote_address) const; + +#ifdef VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING + bool has_subscribed_eventgroup( + service_t _service, instance_t _instance) const; +#endif // VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING + +private: + std::shared_ptr<routing_manager_stub> stub_; + std::shared_ptr<sd::service_discovery> discovery_; + + std::mutex requested_services_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<major_version_t, + std::map<minor_version_t, std::set<client_t> > + > + > + > requested_services_; + + std::mutex remote_subscribers_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<client_t, + std::set<std::shared_ptr<endpoint_definition> > + > + > + > remote_subscribers_; + + std::shared_ptr<serviceinfo> sd_info_; + + std::mutex version_log_timer_mutex_; + boost::asio::steady_timer version_log_timer_; + + bool if_state_running_; + bool sd_route_set_; + bool routing_running_; + std::mutex pending_sd_offers_mutex_; + std::vector<std::pair<service_t, instance_t>> pending_sd_offers_; +#if defined(__linux__) || defined(ANDROID) + std::shared_ptr<netlink_connector> netlink_connector_; +#endif + + std::mutex pending_offers_mutex_; + // map to store pending offers. + // 1st client id in tuple: client id of new offering application + // 2nd client id in tuple: client id of previously/stored offering application + std::map<service_t, + std::map<instance_t, + std::tuple<major_version_t, minor_version_t, + client_t, client_t>>> pending_offers_; + + std::mutex pending_subscription_mutex_; + + std::mutex remote_subscription_state_mutex_; + std::map<std::tuple<service_t, instance_t, eventgroup_t, client_t>, + subscription_state_e> remote_subscription_state_; + + std::shared_ptr<e2e::e2e_provider> e2e_provider_; + + std::mutex status_log_timer_mutex_; + boost::asio::steady_timer status_log_timer_; + + std::mutex memory_log_timer_mutex_; + boost::asio::steady_timer memory_log_timer_; + + std::shared_ptr<endpoint_manager_impl> ep_mgr_impl_; + + reboot_notification_handler_t reboot_notification_handler_; + + routing_ready_handler_t routing_ready_handler_; + routing_state_handler_t routing_state_handler_; + + std::mutex pending_remote_offers_mutex_; + pending_remote_offer_id_t pending_remote_offer_id_; + std::map<pending_remote_offer_id_t, std::pair<service_t, instance_t>> pending_remote_offers_; + + std::chrono::steady_clock::time_point last_resume_; + + std::mutex offer_serialization_mutex_; + std::map<std::pair<service_t, instance_t>, std::deque<std::tuple<uint8_t, client_t, major_version_t, minor_version_t>>> offer_commands_; + + std::mutex callback_counts_mutex_; + std::map<uint32_t, uint16_t> callback_counts_; + + std::mutex statistics_log_timer_mutex_; + boost::asio::steady_timer statistics_log_timer_; + + std::mutex message_statistics_mutex_; + std::map<std::tuple<service_t, instance_t, method_t>, + msg_statistic_t> message_statistics_; + std::tuple<service_t, instance_t, method_t> message_to_discard_; + uint32_t ignored_statistics_counter_; + + // synchronize update_remote_subscription() and send_(un)subscription() + std::mutex update_remote_subscription_mutex_; + + message_acceptance_handler_t message_acceptance_handler_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub.hpp new file mode 100644 index 00000000000..23bedc3205a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub.hpp @@ -0,0 +1,304 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_STUB_ +#define VSOMEIP_V3_ROUTING_MANAGER_STUB_ + +#include <condition_variable> +#include <list> +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <thread> +#include <atomic> +#include <unordered_set> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/handler.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "types.hpp" +#include "../include/routing_host.hpp" +#include "../../endpoints/include/endpoint_host.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../protocol/include/routing_info_entry.hpp" + +namespace vsomeip_v3 { + +class configuration; +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +class netlink_connector; +#endif // __linux__ || ANDROID +class routing_manager_stub_host; + +struct debounce_filter_impl_t; +struct policy; + +class routing_manager_stub: public routing_host, + public std::enable_shared_from_this<routing_manager_stub> { +public: + routing_manager_stub( + routing_manager_stub_host *_host, + const std::shared_ptr<configuration>& _configuration); + virtual ~routing_manager_stub(); + + void init(); + void start(); + void stop(); + + void on_message(const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port); + + void on_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor); + void on_stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor); + + bool send_subscribe( + const std::shared_ptr<endpoint> &_target, client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + remote_subscription_id_t _id); + + bool send_unsubscribe(const std::shared_ptr<endpoint>& _target, + client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id); + + bool send_expired_subscription(const std::shared_ptr<endpoint>& _target, + client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id); + + void send_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event); + + void send_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event); + + bool contained_in_routing_info(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) const; + + void create_local_receiver(); + bool send_ping(client_t _client); + bool is_registered(client_t _client) const; + client_t get_client() const; + void handle_credentials(const client_t _client, std::set<protocol::service> &_requests); + void handle_requests(const client_t _client, std::set<protocol::service> &_requests); + + void update_registration(client_t _client, registration_type_e _type, + const boost::asio::ip::address &_address, port_t _port); + + void print_endpoint_status() const; + + bool send_provided_event_resend_request(client_t _client, + pending_remote_offer_id_t _id); + +#ifndef VSOMEIP_DISABLE_SECURITY + bool update_security_policy_configuration(uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy, + const std::shared_ptr<payload> &_payload, + const security_update_handler_t &_handler); + bool remove_security_policy_configuration(uid_t _uid, gid_t _gid, + const security_update_handler_t &_handler); + void on_security_update_response(pending_security_update_id_t _id, + client_t _client); + + void policy_cache_add(uid_t _uid, const std::shared_ptr<payload>& _payload); + void policy_cache_remove(uid_t _uid); + bool is_policy_cached(uid_t _uid); + + bool send_update_security_policy_request(client_t _client, + pending_security_update_id_t _update_id, uid_t _uid, + const std::shared_ptr<payload>& _payload); + bool send_remove_security_policy_request(client_t _client, + pending_security_update_id_t _update_id, uid_t _uid, gid_t _gid); + + bool send_cached_security_policies(client_t _client); + + bool add_requester_policies(uid_t _uid, gid_t _gid, + const std::set<std::shared_ptr<policy> > &_policies); + void remove_requester_policies(uid_t _uid, gid_t _gid); +#endif // !VSOMEIP_DISABLE_SECURITY + + void add_known_client(client_t _client, const std::string &_client_host); + + void send_suspend() const; + + void remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port); + + routing_state_e get_routing_state(); + +private: + void broadcast(const std::vector<byte_t> &_command) const; + + void on_register_application(client_t _client); + void on_deregister_application(client_t _client); + + void on_offered_service_request(client_t _client, offer_type_e _offer_type); + + void distribute_credentials(client_t _hoster, service_t _service, instance_t _instance); + + void inform_requesters(client_t _hoster, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, protocol::routing_info_entry_type_e _entry, + bool _inform_service); + + void broadcast_ping() const; + void on_pong(client_t _client); + void start_watchdog(); + void check_watchdog(); + + void client_registration_func(void); + void init_routing_endpoint(); + void on_ping_timer_expired(boost::system::error_code const &_error); + void remove_from_pinged_clients(client_t _client); + void set_routing_state(routing_state_e _routing_state) { + (void)_routing_state; + }; + + inline bool is_connected(client_t _source, client_t _sink) const { + + auto find_source = connection_matrix_.find(_source); + if (find_source != connection_matrix_.end()) + return (find_source->second.find(_sink) + != find_source->second.end()); + + return false; + } + inline void add_connection(client_t _source, client_t _sink) { + + connection_matrix_[_source].insert(_sink); + } + inline void remove_connection(client_t _source, client_t _sink) { + + auto find_source = connection_matrix_.find(_source); + if (find_source != connection_matrix_.end()) + find_source->second.erase(_sink); + } + inline void remove_source(client_t _source) { + + connection_matrix_.erase(_source); + } + + void send_client_routing_info(const client_t _target, + protocol::routing_info_entry &_entry); + void send_client_routing_info(const client_t _target, + std::vector<protocol::routing_info_entry> &&_entries); + void send_client_credentials(client_t _target, std::set<std::pair<uid_t, gid_t>> &_credentials); + + void on_client_id_timer_expired(boost::system::error_code const &_error); + + void get_requester_policies(uid_t _uid, gid_t _gid, + std::set<std::shared_ptr<policy> > &_policies) const; + bool send_requester_policies(const std::unordered_set<client_t> &_clients, + const std::set<std::shared_ptr<policy> > &_policies); + + void on_security_update_timeout( + const boost::system::error_code &_error, + pending_security_update_id_t _id, + std::shared_ptr<boost::asio::steady_timer> _timer); + + pending_security_update_id_t pending_security_update_add( + const std::unordered_set<client_t> &_clients); + + std::unordered_set<client_t> pending_security_update_get( + pending_security_update_id_t _id); + + bool pending_security_update_remove( + pending_security_update_id_t _id, client_t _client); + + bool is_pending_security_update_finished( + pending_security_update_id_t _id); + + void add_pending_security_update_handler( + pending_security_update_id_t _id, + const security_update_handler_t &_handler); + void add_pending_security_update_timer( + pending_security_update_id_t _id); + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + void on_net_state_change(bool _is_interface, const std::string &_name, bool _is_available); +#endif + +private: + routing_manager_stub_host *host_; + boost::asio::io_context &io_; + std::mutex watchdog_timer_mutex_; + boost::asio::steady_timer watchdog_timer_; + + boost::asio::steady_timer client_id_timer_; + std::set<client_t> used_client_ids_; + std::mutex used_client_ids_mutex_; + + std::shared_ptr<endpoint> root_; // Routing manager endpoint + + std::shared_ptr<endpoint> local_receiver_; + std::mutex local_receiver_mutex_; + + std::map<client_t, + std::pair<uint8_t, std::map<service_t, std::map<instance_t, std::pair<major_version_t, minor_version_t>> > > > routing_info_; + mutable std::mutex routing_info_mutex_; + std::shared_ptr<configuration> configuration_; + + bool is_socket_activated_; + std::atomic<bool> client_registration_running_; + std::shared_ptr<std::thread> client_registration_thread_; + std::mutex client_registration_mutex_; + std::condition_variable client_registration_condition_; + + std::map<client_t, std::vector<registration_type_e>> pending_client_registrations_; + std::map<client_t, std::pair<boost::asio::ip::address, port_t> > internal_client_ports_; + const std::uint32_t max_local_message_size_; + const std::chrono::milliseconds configured_watchdog_timeout_; + boost::asio::steady_timer pinged_clients_timer_; + std::mutex pinged_clients_mutex_; + std::map<client_t, boost::asio::steady_timer::time_point> pinged_clients_; + + std::map<client_t, std::map<service_t, std::map<instance_t, std::pair<major_version_t, minor_version_t> > > > service_requests_; + std::map<client_t, std::set<client_t>> connection_matrix_; + + std::mutex pending_security_updates_mutex_; + pending_security_update_id_t pending_security_update_id_; + std::map<pending_security_update_id_t, std::unordered_set<client_t>> pending_security_updates_; + + std::recursive_mutex security_update_handlers_mutex_; + std::map<pending_security_update_id_t, security_update_handler_t> security_update_handlers_; + + std::mutex security_update_timers_mutex_; + std::map<pending_security_update_id_t, std::shared_ptr<boost::asio::steady_timer>> security_update_timers_; + + std::mutex updated_security_policies_mutex_; + std::map<uint32_t, std::shared_ptr<payload>> updated_security_policies_; + + mutable std::mutex requester_policies_mutex_; + std::map<uint32_t, + std::map<uint32_t, + std::set<std::shared_ptr<policy> > + > + > requester_policies_; + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + // netlink connector for internal network + // (replacement for Unix Domain Sockets if configured) + std::shared_ptr<netlink_connector> local_link_connector_; + bool is_local_link_available_; +#endif +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_STUB_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub_host.hpp new file mode 100644 index 00000000000..2b1c9079c27 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/routing_manager_stub_host.hpp @@ -0,0 +1,134 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_ +#define VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_ + +#include <boost/asio/io_context.hpp> +#include <vsomeip/handler.hpp> +#include <vsomeip/vsomeip_sec.h> +#include "types.hpp" + +namespace vsomeip_v3 { + +struct debounce_filter_impl_t; +class endpoint_manager_impl; + +class routing_manager_stub_host { +public: + virtual ~routing_manager_stub_host() { + } + + virtual bool offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, bool _must_queue = true) = 0; + + virtual void stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor, bool _must_queue = true) = 0; + + virtual void request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; + + virtual void release_service(client_t _client, service_t _service, + instance_t _instance) = 0; + + virtual void register_shadow_event(client_t _client, service_t _service, + instance_t _instance, event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, event_type_e _type, + reliability_type_e _reliability, bool _is_provided, + bool _is_cyclic) = 0; + + virtual void unregister_shadow_event(client_t _client, service_t _service, + instance_t _instance, event_t _event, bool _is_provided) = 0; + + virtual void subscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, event_t _event, + const std::shared_ptr<debounce_filter_impl_t> &_filter) = 0; + + virtual void on_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _subscription_id) = 0; + + virtual void on_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + bool _remove, remote_subscription_id_t _subscription_id) = 0; + + virtual void unsubscribe(client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) = 0; + + virtual void on_unsubscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + remote_subscription_id_t _unsubscription_id) = 0; + + virtual bool on_message(service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check = 0, bool _is_from_remote = false) = 0; + + virtual void on_notification(client_t _client, service_t _service, + instance_t _instance, const byte_t *_data, length_t _size, + bool _notify_one = false) = 0; + + virtual void on_stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, + minor_version_t _minor) = 0; + + virtual void on_availability(service_t _service, instance_t _instance, + availability_state_e _state, major_version_t _major, + minor_version_t _minor) = 0; + + virtual std::shared_ptr<endpoint> find_local(client_t _client) = 0; + + virtual std::shared_ptr<endpoint> find_or_create_local( + client_t _client) = 0; + virtual void remove_local(client_t _client, bool _remove_local) = 0; + + virtual boost::asio::io_context& get_io() = 0; + virtual client_t get_client() const = 0; + virtual const vsomeip_sec_client_t *get_sec_client() const = 0; + + virtual void on_pong(client_t _client) = 0; + + virtual void handle_client_error(client_t _client) = 0; + + virtual std::shared_ptr<endpoint_manager_impl> get_endpoint_manager() const = 0; + + virtual void on_resend_provided_events_response( + pending_remote_offer_id_t _id) = 0; + + virtual client_t find_local_client(service_t _service, + instance_t _instance) = 0; + + virtual std::set<client_t> find_local_clients(service_t _service, + instance_t _instance) = 0; + + virtual bool is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup) = 0; + + virtual void add_known_client(client_t _client, + const std::string &_client_host) = 0; + + virtual void set_client_host(const std::string &_client_host) = 0; + + virtual bool get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const = 0; + virtual void add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) = 0; + virtual void remove_guest(client_t _client) = 0; + + virtual void clear_local_services() = 0; + + virtual routing_state_e get_routing_state() = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/serviceinfo.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/serviceinfo.hpp new file mode 100644 index 00000000000..c7e87ca5a09 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/serviceinfo.hpp @@ -0,0 +1,93 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SERVICEINFO_HPP_ +#define VSOMEIP_V3_SERVICEINFO_HPP_ + +#include <atomic> +#include <memory> +#include <set> +#include <string> +#include <chrono> +#include <mutex> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +class endpoint; + +class serviceinfo { +public: + VSOMEIP_EXPORT serviceinfo(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + ttl_t _ttl, bool _is_local); + VSOMEIP_EXPORT serviceinfo(const serviceinfo& _other); + VSOMEIP_EXPORT ~serviceinfo(); + + VSOMEIP_EXPORT service_t get_service() const; + VSOMEIP_EXPORT instance_t get_instance() const; + + VSOMEIP_EXPORT major_version_t get_major() const; + VSOMEIP_EXPORT minor_version_t get_minor() const; + + VSOMEIP_EXPORT ttl_t get_ttl() const; + VSOMEIP_EXPORT void set_ttl(ttl_t _ttl); + + VSOMEIP_EXPORT std::chrono::milliseconds get_precise_ttl() const; + VSOMEIP_EXPORT void set_precise_ttl(std::chrono::milliseconds _precise_ttl); + + VSOMEIP_EXPORT std::shared_ptr<endpoint> get_endpoint(bool _reliable) const; + VSOMEIP_EXPORT void set_endpoint(const std::shared_ptr<endpoint>& _endpoint, + bool _reliable); + + VSOMEIP_EXPORT void add_client(client_t _client); + VSOMEIP_EXPORT void remove_client(client_t _client); + VSOMEIP_EXPORT uint32_t get_requesters_size(); + + VSOMEIP_EXPORT bool is_local() const; + + VSOMEIP_EXPORT bool is_in_mainphase() const; + VSOMEIP_EXPORT void set_is_in_mainphase(bool _in_mainphase); + + VSOMEIP_EXPORT bool is_accepting_remote_subscriptions() const; + VSOMEIP_EXPORT void set_accepting_remote_subscriptions(bool _accepting_remote_subscriptions); + + VSOMEIP_EXPORT void add_remote_ip(std::string _remote_ip); + VSOMEIP_EXPORT std::set<std::string, std::less<>> get_remote_ip_accepting_sub(); + +private: + service_t service_; + instance_t instance_; + + major_version_t major_; + minor_version_t minor_; + + mutable std::mutex ttl_mutex_; + std::chrono::milliseconds ttl_; + + std::shared_ptr<endpoint> reliable_; + std::shared_ptr<endpoint> unreliable_; + + mutable std::mutex endpoint_mutex_; + std::mutex requesters_mutex_; + std::set<client_t> requesters_; + + std::atomic_bool is_local_; + std::atomic_bool is_in_mainphase_; + + // Added flag, to ensure the lib only process subscriptions request + // when at least one offer is sent from SD, otherwise will be sent a NACK + // this is needed to avoid desynchronizations triggered by high CPU load + std::atomic_bool accepting_remote_subscription_; // offers sent to multicast + std::set<std::string, std::less<>> + accepting_remote_subscription_from_; // offers sent by unicast + std::mutex accepting_remote_mutex; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERVICEINFO_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/types.hpp new file mode 100644 index 00000000000..3a955018a19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/include/types.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ROUTING_TYPES_HPP_ +#define VSOMEIP_V3_ROUTING_TYPES_HPP_ + +#include <map> +#include <memory> +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/constants.hpp> + +namespace vsomeip_v3 { + +class serviceinfo; +class endpoint_definition; + + +typedef std::map<service_t, + std::map<instance_t, + std::shared_ptr<serviceinfo> > > services_t; + +class eventgroupinfo; + +typedef std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr< + eventgroupinfo> > > > eventgroups_t; + +enum class registration_type_e : std::uint8_t { + REGISTER = 0x1, + DEREGISTER = 0x2, + DEREGISTER_ON_ERROR = 0x3 +}; + +enum class remote_subscription_state_e : std::uint8_t { + SUBSCRIPTION_PENDING = 0x00, + + SUBSCRIPTION_ACKED = 0x01, + SUBSCRIPTION_NACKED = 0x02, + + SUBSCRIPTION_ERROR = 0x03, + SUBSCRIPTION_UNKNOWN = 0xFF +}; + +typedef std::uint16_t remote_subscription_id_t; + +struct msg_statistic_t { + uint32_t counter_; + length_t avg_length_; +}; + +} +// namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ROUTING_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/event.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/event.cpp new file mode 100644 index 00000000000..688baf5ebcf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/event.cpp @@ -0,0 +1,887 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> +#include <sstream> +#include <thread> + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/event.hpp" +#include "../include/routing_manager.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" +#include "../../message/include/payload_impl.hpp" + +namespace vsomeip_v3 { + +event::event(routing_manager *_routing, bool _is_shadow) + : routing_(_routing), + current_(runtime::get()->create_notification()), + update_(runtime::get()->create_notification()), + type_(event_type_e::ET_EVENT), + cycle_timer_(_routing->get_io()), + cycle_(std::chrono::milliseconds::zero()), + change_resets_cycle_(false), + is_updating_on_change_(true), + is_set_(false), + is_provided_(false), + is_shadow_(_is_shadow), + is_cache_placeholder_(false), + epsilon_change_func_(std::bind(&event::has_changed, this, + std::placeholders::_1, std::placeholders::_2)), + has_default_epsilon_change_func_(true), + reliability_(reliability_type_e::RT_UNKNOWN) { + +} + +service_t +event::get_service() const { + + return current_->get_service(); +} + +void +event::set_service(service_t _service) { + + current_->set_service(_service); + update_->set_service(_service); +} + +instance_t +event::get_instance() const { + + return current_->get_instance(); +} + +void +event::set_instance(instance_t _instance) { + + current_->set_instance(_instance); + update_->set_instance(_instance); +} + +major_version_t +event::get_version() const { + + return current_->get_interface_version(); +} + +void +event::set_version(major_version_t _major) { + + current_->set_interface_version(_major); + update_->set_interface_version(_major); +} + +event_t +event::get_event() const { + + return current_->get_method(); +} + +void +event::set_event(event_t _event) { + + current_->set_method(_event); + update_->set_method(_event); +} + +event_type_e +event::get_type() const { + + return type_; +} + +void +event::set_type(const event_type_e _type) { + + type_ = _type; +} + +bool +event::is_field() const { + + return (type_ == event_type_e::ET_FIELD); +} + +bool +event::is_provided() const { + + return is_provided_; +} + +void +event::set_provided(bool _is_provided) { + + is_provided_ = _is_provided; +} + +bool event::is_set() const { + return is_set_; +} + +std::shared_ptr<payload> +event::get_payload() const { + + std::lock_guard<std::mutex> its_lock(mutex_); + return current_->get_payload(); +} + +void +event::update_payload() { + + std::lock_guard<std::mutex> its_lock(mutex_); + update_payload_unlocked(); +} + +void +event::update_payload_unlocked() { + + current_->set_payload(update_->get_payload()); +} + +void +event::set_payload(const std::shared_ptr<payload> &_payload, bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + if (is_provided_) { + if (prepare_update_payload_unlocked(_payload, _force)) { + if (is_updating_on_change_) { + if (change_resets_cycle_) + stop_cycle(); + + notify(_force); + + if (change_resets_cycle_) + start_cycle(); + + update_payload_unlocked(); + } + } + } else { + VSOMEIP_INFO << __func__ << ":" << __LINE__ + << " Cannot set payload for event [" + << std::hex << std::setw(4) << std::setfill('0') + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; + } +} + +void +event::set_payload(const std::shared_ptr<payload> &_payload, client_t _client, + bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + if (is_provided_) { + if (prepare_update_payload_unlocked(_payload, _force)) { + if (is_updating_on_change_) { + notify_one_unlocked(_client, _force); + update_payload_unlocked(); + } + } + } else { + VSOMEIP_INFO << __func__ << ":" << __LINE__ + << " Cannot set payload for event [" + << std::hex << std::setw(4) << std::setfill('0') + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; + } +} + +void +event::set_payload(const std::shared_ptr<payload> &_payload, + const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + if (is_provided_) { + if (prepare_update_payload_unlocked(_payload, _force)) { + if (is_updating_on_change_) { + notify_one_unlocked(_client, _target); + update_payload_unlocked(); + } + } + } else { + VSOMEIP_INFO << __func__ << ":" << __LINE__ + << " Cannot set payload for event [" + << std::hex << std::setw(4) << std::setfill('0') + << current_->get_service() << "." + << current_->get_instance() << "." + << current_->get_method() + << "]. It isn't provided"; + } +} + +bool +event::set_payload_notify_pending(const std::shared_ptr<payload> &_payload) { + + std::lock_guard<std::mutex> its_lock(mutex_); + if (is_provided_ && !is_set_) { + + update_->set_payload(_payload); + is_set_ = true; + + // Send pending initial events. + for (const auto &its_target : pending_) { + set_session(); + routing_->send_to(VSOMEIP_ROUTING_CLIENT, + its_target, update_); + } + pending_.clear(); + + update_payload_unlocked(); + + return true; + } + + return false; +} + +void +event::unset_payload(bool _force) { + std::lock_guard<std::mutex> its_lock(mutex_); + if (_force) { + is_set_ = false; + stop_cycle(); + current_->set_payload(std::make_shared<payload_impl>()); + } else { + if (is_provided_) { + is_set_ = false; + stop_cycle(); + current_->set_payload(std::make_shared<payload_impl>()); + } + } +} + +void +event::set_update_cycle(std::chrono::milliseconds &_cycle) { + + if (is_provided_) { + std::lock_guard<std::mutex> its_lock(mutex_); + stop_cycle(); + cycle_ = _cycle; + start_cycle(); + } +} + +void +event::set_change_resets_cycle(bool _change_resets_cycle) { + + change_resets_cycle_ = _change_resets_cycle; +} + +void +event::set_update_on_change(bool _is_active) { + + if (is_provided_) { + is_updating_on_change_ = _is_active; + } +} + +void +event::set_epsilon_change_function( + const epsilon_change_func_t &_epsilon_change_func) { + + std::lock_guard<std::mutex> its_lock(mutex_); + if (_epsilon_change_func) { + epsilon_change_func_ = _epsilon_change_func; + has_default_epsilon_change_func_ = false; + } +} + +std::set<eventgroup_t> +event::get_eventgroups() const { + + std::set<eventgroup_t> its_eventgroups; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (const auto& e : eventgroups_) { + its_eventgroups.insert(e.first); + } + } + return its_eventgroups; +} + +std::set<eventgroup_t> +event::get_eventgroups(client_t _client) const { + + std::set<eventgroup_t> its_eventgroups; + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (auto e : eventgroups_) { + if (e.second.find(_client) != e.second.end()) + its_eventgroups.insert(e.first); + } + return its_eventgroups; +} + +void +event::add_eventgroup(eventgroup_t _eventgroup) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + if (eventgroups_.find(_eventgroup) == eventgroups_.end()) + eventgroups_[_eventgroup] = std::set<client_t>(); +} + +void +event::set_eventgroups(const std::set<eventgroup_t> &_eventgroups) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (auto e : _eventgroups) + eventgroups_[e] = std::set<client_t>(); +} + +void +event::update_cbk(boost::system::error_code const &_error) { + + if (!_error) { + std::lock_guard<std::mutex> its_lock(mutex_); + cycle_timer_.expires_from_now(cycle_); + notify(true); + auto its_handler = + std::bind(&event::update_cbk, shared_from_this(), + std::placeholders::_1); + cycle_timer_.async_wait(its_handler); + } +} + +void +event::notify(bool _force) { + + if (is_set_) { + set_session(); + routing_->send(VSOMEIP_ROUTING_CLIENT, update_, _force); + } else { + VSOMEIP_INFO << __func__ + << ": Notifying " + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." << get_event() + << " failed. Event payload not (yet) set!"; + } +} + +void +event::notify_one(client_t _client, + const std::shared_ptr<endpoint_definition> &_target) { + + if (_target) { + std::lock_guard<std::mutex> its_lock(mutex_); + notify_one_unlocked(_client, _target); + } else { + VSOMEIP_WARNING << __func__ + << ": Notifying " + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." << get_event() + << " failed. Target undefined"; + } +} + +void +event::notify_one_unlocked(client_t _client, + const std::shared_ptr<endpoint_definition> &_target) { + + if (_target) { + if (is_set_) { + set_session(); + routing_->send_to(_client, _target, update_); + } else { + VSOMEIP_INFO << __func__ + << ": Notifying " + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." << get_event() + << " failed. Event payload not (yet) set!"; + pending_.insert(_target); + } + } else { + VSOMEIP_WARNING << __func__ + << ": Notifying " + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." << get_event() + << " failed. Target undefined"; + } +} + +void +event::notify_one(client_t _client, bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + notify_one_unlocked(_client, _force); +} + +void +event::notify_one_unlocked(client_t _client, bool _force) { + + if (is_set_) { + set_session(); + routing_->send(_client, update_, _force); + } else { + VSOMEIP_INFO << __func__ + << ": Initial value for [" + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." << get_event() + << "] not yet set by the service/client." + << " Client " << _client + << " will not receive any initial notification!"; + } +} + +bool +event::prepare_update_payload(const std::shared_ptr<payload> &_payload, + bool _force) { + + std::lock_guard<std::mutex> its_lock(mutex_); + return prepare_update_payload_unlocked(_payload, _force); +} + +bool +event::prepare_update_payload_unlocked( + const std::shared_ptr<payload> &_payload, bool _force) { + + if (!_force && type_ == event_type_e::ET_FIELD && cycle_ == std::chrono::milliseconds::zero() + && !has_changed(current_->get_payload(), _payload) && !is_shadow_) { + return false; + } + + update_->set_payload(_payload); + + if (!is_set_) { + start_cycle(); + is_set_ = true; + } + + return true; +} + +void +event::add_ref(client_t _client, bool _is_provided) { + + std::lock_guard<std::mutex> its_lock(refs_mutex_); + auto its_client = refs_.find(_client); + if (its_client == refs_.end()) { + refs_[_client][_is_provided] = 1; + } else { + auto its_provided = its_client->second.find(_is_provided); + if (its_provided == its_client->second.end()) { + refs_[_client][_is_provided] = 1; + } else { + its_provided->second++; + } + } +} + +void +event::remove_ref(client_t _client, bool _is_provided) { + + std::lock_guard<std::mutex> its_lock(refs_mutex_); + auto its_client = refs_.find(_client); + if (its_client != refs_.end()) { + auto its_provided = its_client->second.find(_is_provided); + if (its_provided != its_client->second.end()) { + its_provided->second--; + if (0 == its_provided->second) { + its_client->second.erase(_is_provided); + if (0 == its_client->second.size()) { + refs_.erase(_client); + } + } + } + } +} + +bool +event::has_ref() { + + std::lock_guard<std::mutex> its_lock(refs_mutex_); + return refs_.size() != 0; +} + +bool +event::add_subscriber(eventgroup_t _eventgroup, + const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client, bool _force) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + bool ret = false; + if (_force // remote events managed by rm_impl + || is_provided_ // events provided by rm_proxies + || is_shadow_ // local events managed by rm_impl + || is_cache_placeholder_) { + + if (_filter) { + VSOMEIP_WARNING << "Using client [" + << std::hex << std::setw(4) << std::setfill('0') + << _client + << "] specific filter configuration for SOME/IP event " + << get_service() << "." << get_instance() << "." << get_event() << "."; + std::stringstream its_filter_parameters; + its_filter_parameters << "(on_change=" + << std::boolalpha << _filter->on_change_ + << ", interval=" << std::dec << _filter->interval_ + << ", on_change_resets_interval=" + << std::boolalpha << _filter->on_change_resets_interval_ + << ", ignore=[ "; + for (auto i : _filter->ignore_) + its_filter_parameters << "(" << std::dec << i.first << ", " + << std::hex << std::setw(2) << std::setfill('0') + << (int)i.second << ") "; + its_filter_parameters << "])"; + VSOMEIP_INFO << "Filter parameters: " + << its_filter_parameters.str(); + { + std::scoped_lock lk {filters_mutex_}; + filters_[_client] = [_filter]( + const std::shared_ptr<payload> &_old, + const std::shared_ptr<payload> &_new) { + + bool is_changed(false), is_elapsed(false); + + // Check whether we should forward because of changed data + if (_filter->on_change_) { + length_t its_min_length, its_max_length; + + if (_old->get_length() < _new->get_length()) { + its_min_length = _old->get_length(); + its_max_length = _new->get_length(); + } else { + its_min_length = _new->get_length(); + its_max_length = _old->get_length(); + } + + // Check whether all additional bytes (if any) are excluded + for (length_t i = its_min_length; i < its_max_length; i++) { + auto j = _filter->ignore_.find(i); + // A change is detected when an additional byte is not + // excluded at all or if its exclusion does not cover all + // bits + if (j == _filter->ignore_.end() || j->second != 0xFF) { + is_changed = true; + break; + } + } + + if (!is_changed) { + const byte_t *its_old = _old->get_data(); + const byte_t *its_new = _new->get_data(); + for (length_t i = 0; i < its_min_length; i++) { + auto j = _filter->ignore_.find(i); + if (j == _filter->ignore_.end()) { + if (its_old[i] != its_new[i]) { + is_changed = true; + break; + } + } else if (j->second != 0xFF) { + if ((its_old[i] & ~(j->second)) != (its_new[i] & ~(j->second))) { + is_changed = true; + break; + } + } + } + } + } + + if (_filter->interval_ > -1) { + // Check whether we should forward because of the elapsed time since + // we did last time + std::chrono::steady_clock::time_point its_current + = std::chrono::steady_clock::now(); + + int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - _filter->last_forwarded_).count(); + is_elapsed = (_filter->last_forwarded_ == std::chrono::steady_clock::time_point::max() + || elapsed >= _filter->interval_); + if (is_elapsed || (is_changed && _filter->on_change_resets_interval_)) + _filter->last_forwarded_ = its_current; } + + return (is_changed || is_elapsed); + }; + } + + // Create a new callback for this client if filter interval is used + routing_->register_debounce(_filter, _client, shared_from_this()); + } else { + std::scoped_lock lk {filters_mutex_}; + filters_.erase(_client); + } + + ret = eventgroups_[_eventgroup].insert(_client).second; + + } else { + VSOMEIP_WARNING << __func__ << ": Didnt' insert client " + << std::hex << std::setw(4) << std::setfill('0') << _client + << " to eventgroup 0x" + << std::hex << std::setw(4) << std::setfill('0') + << get_service() << "." << get_instance() << "." + << _eventgroup; + } + return ret; +} + +void +event::remove_subscriber(eventgroup_t _eventgroup, client_t _client) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto find_eventgroup = eventgroups_.find(_eventgroup); + if (find_eventgroup != eventgroups_.end()) { + find_eventgroup->second.erase(_client); + routing_->remove_debounce(_client, get_event()); + } +} + +bool +event::has_subscriber(eventgroup_t _eventgroup, client_t _client) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto find_eventgroup = eventgroups_.find(_eventgroup); + if (find_eventgroup != eventgroups_.end()) { + if (_client == ANY_CLIENT) { + return (find_eventgroup->second.size() > 0); + } else { + return (find_eventgroup->second.find(_client) + != find_eventgroup->second.end()); + } + } + return false; +} + +std::set<client_t> +event::get_subscribers() { + + std::set<client_t> its_subscribers; + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (const auto &e : eventgroups_) + its_subscribers.insert(e.second.begin(), e.second.end()); + return its_subscribers; +} + +std::set<client_t> +event::get_filtered_subscribers(bool _force) { + + std::set<client_t> its_subscribers(get_subscribers()); + std::set<client_t> its_filtered_subscribers; + + std::shared_ptr<payload> its_payload, its_payload_update; + { + its_payload = current_->get_payload(); + its_payload_update = update_->get_payload(); + } + + bool is_filters_empty = false; + { + std::scoped_lock its_lock {filters_mutex_}; + is_filters_empty = filters_.empty(); + } + + if (is_filters_empty) { + + bool must_forward = ((type_ != event_type_e::ET_FIELD + && has_default_epsilon_change_func_) + || _force + || epsilon_change_func_(its_payload, its_payload_update)); + + if (must_forward) + return its_subscribers; + + } else { + byte_t is_allowed(0xff); + + std::scoped_lock its_lock {filters_mutex_}; + for (const auto s : its_subscribers) { + + auto its_specific = filters_.find(s); + if (its_specific != filters_.end()) { + if (its_specific->second(its_payload, its_payload_update)) + its_filtered_subscribers.insert(s); + } else { + if (is_allowed == 0xff) { + is_allowed = ((type_ != event_type_e::ET_FIELD + && has_default_epsilon_change_func_) + || _force + || epsilon_change_func_(its_payload, its_payload_update) + ? 0x01 : 0x00); + } + + if (is_allowed == 0x01) + its_filtered_subscribers.insert(s); + } + } + } + + return its_filtered_subscribers; +} + +// Get the clients that have pending updates after debounce timeout +void +event::get_pending_updates(const std::set<client_t> &_clients) { + if(has_changed(current_->get_payload(), update_->get_payload())) { + routing_->update_debounce_clients(_clients, get_event()); + } +} + +std::set<client_t> +event::update_and_get_filtered_subscribers( + const std::shared_ptr<payload> &_payload, bool _is_from_remote) { + + std::lock_guard<std::mutex> its_lock(mutex_); + + (void)prepare_update_payload_unlocked(_payload, true); + auto its_subscribers = get_filtered_subscribers(!_is_from_remote); + get_pending_updates(its_subscribers); + if (_is_from_remote) + update_payload_unlocked(); + + return its_subscribers; +} + +void +event::clear_subscribers() { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (auto &e : eventgroups_) + e.second.clear(); +} + +bool +event::has_ref(client_t _client, bool _is_provided) { + + std::lock_guard<std::mutex> its_lock(refs_mutex_); + auto its_client = refs_.find(_client); + if (its_client != refs_.end()) { + auto its_provided = its_client->second.find(_is_provided); + if (its_provided != its_client->second.end()) { + if(its_provided->second > 0) { + return true; + } + } + } + return false; +} + +bool +event::is_shadow() const { + + return is_shadow_; +} + +void +event::set_shadow(bool _shadow) { + + is_shadow_ = _shadow; +} + +bool +event::is_cache_placeholder() const { + + return is_cache_placeholder_; +} + +void +event::set_cache_placeholder(bool _is_cache_place_holder) { + + is_cache_placeholder_ = _is_cache_place_holder; +} + +void +event::start_cycle() { + + if (!is_shadow_ + && std::chrono::milliseconds::zero() != cycle_) { + cycle_timer_.expires_from_now(cycle_); + auto its_handler = + std::bind(&event::update_cbk, shared_from_this(), + std::placeholders::_1); + cycle_timer_.async_wait(its_handler); + } +} + +void +event::stop_cycle() { + + if (!is_shadow_ + && std::chrono::milliseconds::zero() != cycle_) { + boost::system::error_code ec; + cycle_timer_.cancel(ec); + } +} + +bool +event::has_changed(const std::shared_ptr<payload> &_lhs, + const std::shared_ptr<payload> &_rhs) const { + + if (_lhs) { + if (_rhs) { + return !((*_lhs) == (*_rhs)); + } else { + return false; + } + } else { + if (_rhs) { + return false; + } + } + + return true; // both are nullptr +} + +std::set<client_t> +event::get_subscribers(eventgroup_t _eventgroup) { + + std::set<client_t> its_subscribers; + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_eventgroup = eventgroups_.find(_eventgroup); + if (found_eventgroup != eventgroups_.end()) { + its_subscribers = found_eventgroup->second; + } + return its_subscribers; +} + +bool +event::is_subscribed(client_t _client) { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + for (const auto &egp : eventgroups_) { + if (egp.second.find(_client) != egp.second.end()) { + return true; + } + } + return false; +} + +reliability_type_e +event::get_reliability() const { + + return reliability_; +} + +void +event::set_reliability(const reliability_type_e _reliability) { + + reliability_ = _reliability; +} + +void +event::remove_pending(const std::shared_ptr<endpoint_definition> &_target) { + + std::lock_guard<std::mutex> its_lock(mutex_); + pending_.erase(_target); +} + +void +event::set_session() { + + update_->set_session(routing_->get_session(false)); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/eventgroupinfo.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/eventgroupinfo.cpp new file mode 100644 index 00000000000..e5f2a6d23d8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/eventgroupinfo.cpp @@ -0,0 +1,530 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <algorithm> +#include <iomanip> + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/eventgroupinfo.hpp" +#include "../include/event.hpp" +#include "../include/remote_subscription.hpp" +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID +#include "../../endpoints/include/endpoint_definition.hpp" + +namespace vsomeip_v3 { + +eventgroupinfo::eventgroupinfo() + : service_(0), + instance_(0), + eventgroup_(0), + major_(DEFAULT_MAJOR), + ttl_(DEFAULT_TTL), + port_(ILLEGAL_PORT), + threshold_(0), + id_(PENDING_SUBSCRIPTION_ID), + reliability_(reliability_type_e::RT_UNKNOWN), + reliability_auto_mode_(false), + max_remote_subscribers_(VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS) { +} + +eventgroupinfo::eventgroupinfo( + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, const major_version_t _major, + const ttl_t _ttl, const uint8_t _max_remote_subscribers) + : service_(_service), + instance_(_instance), + eventgroup_(_eventgroup), + major_(_major), + ttl_(_ttl), + port_(ILLEGAL_PORT), + threshold_(0), + id_(PENDING_SUBSCRIPTION_ID), + reliability_(reliability_type_e::RT_UNKNOWN), + reliability_auto_mode_(false), + max_remote_subscribers_(_max_remote_subscribers) { +} + +eventgroupinfo::~eventgroupinfo() { +} + +service_t eventgroupinfo::get_service() const { + return service_; +} + +void eventgroupinfo::set_service(const service_t _service) { + service_ = _service; +} + +instance_t eventgroupinfo::get_instance() const { + return instance_; +} + +void eventgroupinfo::set_instance(const instance_t _instance) { + instance_ = _instance; +} + +eventgroup_t eventgroupinfo::get_eventgroup() const { + return eventgroup_; +} + +void eventgroupinfo::set_eventgroup(const eventgroup_t _eventgroup) { + eventgroup_ = _eventgroup; +} + +major_version_t eventgroupinfo::get_major() const { + return major_; +} + +void eventgroupinfo::set_major(const major_version_t _major) { + major_ = _major; +} + +ttl_t eventgroupinfo::get_ttl() const { + return ttl_; +} + +void eventgroupinfo::set_ttl(const ttl_t _ttl) { + ttl_ = _ttl; +} + +bool eventgroupinfo::is_multicast() const { + std::lock_guard<std::mutex> its_lock(address_mutex_); + return address_.is_multicast(); +} + +bool eventgroupinfo::is_sending_multicast() const { + return (is_multicast() && + threshold_ != 0 && + get_unreliable_target_count() >= threshold_); +} + +bool eventgroupinfo::get_multicast(boost::asio::ip::address &_address, + uint16_t &_port) const { + std::lock_guard<std::mutex> its_lock(address_mutex_); + if (address_.is_multicast()) { + _address = address_; + _port = port_; + return true; + } + return false; +} + +void eventgroupinfo::set_multicast(const boost::asio::ip::address &_address, + uint16_t _port) { + std::lock_guard<std::mutex> its_lock(address_mutex_); + address_ = _address; + port_ = _port; +} + +std::set<std::shared_ptr<event> > eventgroupinfo::get_events() const { + std::lock_guard<std::mutex> its_lock(events_mutex_); + return events_; +} + +void eventgroupinfo::add_event(const std::shared_ptr<event>& _event) { + + if (_event == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return; + } + + std::lock_guard<std::mutex> its_lock(events_mutex_); + events_.insert(_event); + + if (!reliability_auto_mode_ && + _event->get_reliability() == reliability_type_e::RT_UNKNOWN) { + reliability_auto_mode_ = true; + return; + } + + switch (_event->get_reliability()) { + case reliability_type_e::RT_RELIABLE: + if (reliability_ == reliability_type_e::RT_UNRELIABLE) { + reliability_ = reliability_type_e::RT_BOTH; + } else if (reliability_ != reliability_type_e::RT_BOTH) { + reliability_ = reliability_type_e::RT_RELIABLE; + } + break; + case reliability_type_e::RT_UNRELIABLE: + if (reliability_ == reliability_type_e::RT_RELIABLE) { + reliability_ = reliability_type_e::RT_BOTH; + } else if (reliability_ != reliability_type_e::RT_BOTH) { + reliability_ = reliability_type_e::RT_UNRELIABLE; + } + break; + case reliability_type_e::RT_BOTH: + reliability_ = reliability_type_e::RT_BOTH; + break; + default: + ; + } +} + +void eventgroupinfo::remove_event(const std::shared_ptr<event>& _event) { + + if (_event == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return; + } + + std::lock_guard<std::mutex> its_lock(events_mutex_); + events_.erase(_event); +} + +reliability_type_e eventgroupinfo::get_reliability() const { + return reliability_; +} + +void eventgroupinfo::set_reliability(reliability_type_e _reliability) { + reliability_ = _reliability; +} + +bool eventgroupinfo::is_reliability_auto_mode() const { + return reliability_auto_mode_; +} + +uint32_t +eventgroupinfo::get_unreliable_target_count() const { + uint32_t its_count(0); + + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + for (const auto &s : subscriptions_) { + auto its_subscription = s.second; + if (!its_subscription->get_parent() + && its_subscription->get_unreliable()) { + its_count++; + } + } + + return its_count; +} + +uint8_t eventgroupinfo::get_threshold() const { + return threshold_; +} + +void eventgroupinfo::set_threshold(uint8_t _threshold) { + threshold_ = _threshold; +} + +std::set<std::shared_ptr<remote_subscription> > +eventgroupinfo::get_remote_subscriptions() const { + std::set<std::shared_ptr<remote_subscription> > its_subscriptions; + + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + for (const auto &i : subscriptions_) + its_subscriptions.insert(i.second); + + return its_subscriptions; +} + +bool +eventgroupinfo::update_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription, + const std::chrono::steady_clock::time_point &_expiration, + std::set<client_t> &_changed, remote_subscription_id_t &_id, + const bool _is_subscribe) { + + bool its_result(false); + + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return its_result; + } + + std::shared_ptr<endpoint_definition> its_subscriber; + std::set<std::shared_ptr<event> > its_events; + + { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + + for (const auto &its_item : subscriptions_) { + if (its_item.second->equals(_subscription)) { + // update existing subscription + _changed = its_item.second->update( + _subscription->get_clients(), _expiration, _is_subscribe); + _id = its_item.second->get_id(); + + // Copy acknowledgment states from existing subscription + for (const auto its_client : _subscription->get_clients()) { + auto its_state = its_item.second->get_client_state(its_client); + if (_is_subscribe + && its_state == remote_subscription_state_e::SUBSCRIPTION_UNKNOWN) { + // We met the current subscription object during its + // unsubscribe process. Therefore, trigger a resubscription. + its_state = remote_subscription_state_e::SUBSCRIPTION_PENDING; + _changed.insert(its_client); + } + + _subscription->set_client_state(its_client, its_state); + } + + if (_is_subscribe) { + if (!_changed.empty()) { + // New clients: + // Let this be a child subscription + _subscription->set_parent(its_item.second); + update_id(); + _subscription->set_id(id_); + subscriptions_[id_] = _subscription; + } else { + if (!_subscription->is_pending()) { + if (!_subscription->force_initial_events()) { + _subscription->set_initial(false); + } + } else { + its_item.second->set_answers( + its_item.second->get_answers() + 1); + _subscription->set_parent(its_item.second); + _subscription->set_answers(0); + } + } + } else { + if (its_item.second->is_pending()) { + its_subscriber = its_item.second->get_subscriber(); + } + } + + its_result = true; + break; + } + } + } + + if (its_subscriber) { + { + // Build set of events first to avoid having to + // hold the "events_mutex_" in parallel to the internal event mutexes. + std::lock_guard<std::mutex> its_lock(events_mutex_); + for (const auto &its_event : events_) + its_events.insert(its_event); + } + for (const auto &its_event : its_events) + its_event->remove_pending(its_subscriber); + } + + return its_result; +} + +bool +eventgroupinfo::is_remote_subscription_limit_reached( + const std::shared_ptr<remote_subscription> &_subscription) { + bool limit_reached(false); + + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return limit_reached; + } + + if (subscriptions_.size() <= max_remote_subscribers_) { + return false; + } + + boost::asio::ip::address its_address; + if (_subscription->get_ip_address(its_address)) { + auto find_address = remote_subscribers_count_.find(its_address); + if (find_address != remote_subscribers_count_.end()) { + if (find_address->second > max_remote_subscribers_) { + VSOMEIP_WARNING << ": remote subscriber limit [" << std::dec + << (uint32_t)max_remote_subscribers_ << "] to [" + << std::hex << std::setfill('0') + << std::setw(4) << service_ << "." + << std::setw(4) << instance_ << "." + << std::setw(4) << eventgroup_ << "]" + << " reached for remote address: " << its_address.to_string() + << " rejecting subscription!"; + return true; + } + } + } + return limit_reached; +} + +remote_subscription_id_t +eventgroupinfo::add_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription) { + + if (_subscription == nullptr) { + VSOMEIP_ERROR << __func__ << ": Received ptr is null"; + return id_; + } + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + + update_id(); + + _subscription->set_id(id_); + subscriptions_[id_] = _subscription; + + boost::asio::ip::address its_address; + if (_subscription->get_ip_address(its_address)) { + remote_subscribers_count_[its_address]++; + } + return id_; +} + +std::shared_ptr<remote_subscription> +eventgroupinfo::get_remote_subscription( + const remote_subscription_id_t _id) { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + + auto find_subscription = subscriptions_.find(_id); + if (find_subscription != subscriptions_.end()) + return find_subscription->second; + + return nullptr; +} + +void +eventgroupinfo::remove_remote_subscription( + const remote_subscription_id_t _id) { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + + auto find_subscription = subscriptions_.find(_id); + if (find_subscription != subscriptions_.end()) { + boost::asio::ip::address its_address; + if (find_subscription->second->get_ip_address(its_address)) { + auto find_address = remote_subscribers_count_.find(its_address); + if (find_address != remote_subscribers_count_.end()) { + if(find_address->second != 0) { + find_address->second--; + } + } + } + } + + subscriptions_.erase(_id); +} + +void +eventgroupinfo::clear_remote_subscriptions() { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + subscriptions_.clear(); + remote_subscribers_count_.clear(); +} + +std::set<std::shared_ptr<endpoint_definition> > +eventgroupinfo::get_unicast_targets() const { + std::set<std::shared_ptr<endpoint_definition>> its_targets; + + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + for (const auto &s : subscriptions_) { + const auto its_reliable = s.second->get_reliable(); + if (its_reliable) + its_targets.insert(its_reliable); + const auto its_unreliable = s.second->get_unreliable(); + if (its_unreliable) + its_targets.insert(its_unreliable); + } + + return its_targets; +} + +std::set<std::shared_ptr<endpoint_definition> > +eventgroupinfo::get_multicast_targets() const { + std::set<std::shared_ptr<endpoint_definition>> its_targets; + return its_targets; +} + +bool eventgroupinfo::is_selective() const { + // Selective eventgroups always contain a single event + std::lock_guard<std::mutex> its_lock(events_mutex_); + if (events_.size() != 1) + return false; + + return ((*events_.begin())->get_type() + == event_type_e::ET_SELECTIVE_EVENT); +} + +void +eventgroupinfo::update_id() { + id_++; + if (id_ == PENDING_SUBSCRIPTION_ID) + id_ = 1; +} + +void +eventgroupinfo::send_initial_events( + const std::shared_ptr<endpoint_definition> &_reliable, + const std::shared_ptr<endpoint_definition> &_unreliable) const { + std::set<std::shared_ptr<event> > its_reliable_events, its_unreliable_events; + + // Build sets of reliable/unreliable events first to avoid having to + // hold the "events_mutex_" in parallel to the internal event mutexes. + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + for (const auto &its_event : events_) { + if (its_event && its_event->get_type() == event_type_e::ET_FIELD) { + auto its_reliability = its_event->get_reliability(); +#ifdef VSOMEIP_ENABLE_COMPAT + if (its_reliability == reliability_type_e::RT_UNKNOWN) { + if (_reliable) { + if (_unreliable) { + its_reliability = reliability_type_e::RT_BOTH; + } else { + its_reliability = reliability_type_e::RT_RELIABLE; + } + } else if (_unreliable) { + its_reliability = reliability_type_e::RT_UNRELIABLE; + } + } +#endif + switch (its_reliability) { + case reliability_type_e::RT_RELIABLE: + its_reliable_events.insert(its_event); + break; + case reliability_type_e::RT_UNRELIABLE: + its_unreliable_events.insert(its_event); + break; + case reliability_type_e::RT_BOTH: + its_reliable_events.insert(its_event); + its_unreliable_events.insert(its_event); + break; + default: + VSOMEIP_WARNING << __func__ << "Event reliability unknown: [" + << std::hex << std::setfill('0') + << std::setw(4) << service_ << "." + << std::setw(4) << instance_ << "." + << std::setw(4) << eventgroup_ << "." + << std::setw(4) << its_event->get_event() << "]"; + } + } + } + } + + // Send events + if (!its_reliable_events.empty()) { + if (_reliable != nullptr) { + for (const auto &its_event : its_reliable_events) + its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _reliable); + } else { + VSOMEIP_ERROR << __func__ << ": Received ptr (_reliable) is null"; + } + } + + if (!its_unreliable_events.empty()) { + if (_unreliable != nullptr) { + for (const auto &its_event : its_unreliable_events) + its_event->notify_one(VSOMEIP_ROUTING_CLIENT, _unreliable); + } else { + VSOMEIP_ERROR << __func__ << ": Received ptr (_unreliable) is null"; + } + } +} + +uint8_t eventgroupinfo::get_max_remote_subscribers() const { + return max_remote_subscribers_; +} + +void eventgroupinfo::set_max_remote_subscribers(uint8_t _max_remote_subscribers) { + max_remote_subscribers_ = _max_remote_subscribers; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/remote_subscription.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/remote_subscription.cpp new file mode 100644 index 00000000000..7f5a1044dbd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/remote_subscription.cpp @@ -0,0 +1,360 @@ +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/remote_subscription.hpp" + +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { + +remote_subscription::remote_subscription() + : id_(PENDING_SUBSCRIPTION_ID), + is_initial_(true), + force_initial_events_(false), + ttl_(DEFAULT_TTL), + reserved_(0), + counter_(0), + answers_(1), + final_destination_{destiny::none} { +} + +remote_subscription::~remote_subscription() { +} + +bool +remote_subscription::operator==( + const remote_subscription &_other) const { + auto own_egi = eventgroupinfo_.lock(); + auto other_egi = _other.eventgroupinfo_.lock(); + bool reliable_equal(true); + if (reliable_ && _other.reliable_) { + reliable_equal = (reliable_ == _other.reliable_); + } + bool unreliable_equal(true); + if (unreliable_ && _other.unreliable_) { + unreliable_equal = (unreliable_ == _other.unreliable_); + } + return (own_egi && other_egi && own_egi == other_egi && unreliable_equal + && reliable_equal); +} + +bool +remote_subscription::equals( + const std::shared_ptr<remote_subscription> &_other) const { + return operator ==(*_other); +} + +bool +remote_subscription::address_equals( + const std::shared_ptr<remote_subscription> &_other) const { + bool relibale_address_equals(false); + bool unrelibale_address_equals(false); + + if (reliable_ && (*_other).reliable_) + relibale_address_equals = (reliable_->get_address() + == (*_other).reliable_->get_address()); + if (unreliable_ && (*_other).unreliable_) + unrelibale_address_equals = (unreliable_->get_address() + == (*_other).unreliable_->get_address()); + return (relibale_address_equals || unrelibale_address_equals); +} + +void +remote_subscription::reset(const std::set<client_t> &_clients) { + auto its_client_state = std::make_pair( + remote_subscription_state_e::SUBSCRIPTION_PENDING, + std::chrono::steady_clock::time_point()); + if (_clients.empty()) { + clients_[0] = its_client_state; + } else { + for (const auto &its_client : _clients) + clients_[its_client] = its_client_state; + } +} + +bool +remote_subscription::is_initial() const { + return is_initial_; +} + +void +remote_subscription::set_initial(const bool _is_initial) { + is_initial_ = _is_initial; +} + +bool +remote_subscription::force_initial_events() const { + return force_initial_events_; +} + +void +remote_subscription::set_force_initial_events( + const bool _force_initial_events) { + force_initial_events_ = _force_initial_events; +} + +remote_subscription_id_t +remote_subscription::get_id() const { + return id_; +} + +void +remote_subscription::set_id(const remote_subscription_id_t _id) { + id_ = _id; +} + +std::shared_ptr<eventgroupinfo> +remote_subscription::get_eventgroupinfo() const { + return eventgroupinfo_.lock(); +} + +void +remote_subscription::set_eventgroupinfo( + const std::shared_ptr<eventgroupinfo> &_info) { + eventgroupinfo_ = _info; +} + +ttl_t +remote_subscription::get_ttl() const { + return ttl_; +} + +void +remote_subscription::set_ttl(const ttl_t _ttl) { + ttl_ = _ttl; +} + +uint16_t +remote_subscription::get_reserved() const { + return reserved_; +} + +void +remote_subscription::set_reserved(const uint16_t _reserved) { + reserved_ = _reserved; +} + +uint8_t +remote_subscription::get_counter() const { + return counter_; +} + +void +remote_subscription::set_counter(uint8_t _counter) { + counter_ = _counter; +} + +std::set<client_t> +remote_subscription::get_clients() const { + std::lock_guard<std::mutex> its_lock(mutex_); + std::set<client_t> its_clients; + for (const auto &its_item : clients_) + its_clients.insert(its_item.first); + return its_clients; +} + +bool +remote_subscription::has_client() const { + std::lock_guard<std::mutex> its_lock(mutex_); + return (clients_.size() > 0); +} + +bool +remote_subscription::has_client(const client_t _client) const { + std::lock_guard<std::mutex> its_lock(mutex_); + return (clients_.find(_client) != clients_.end()); +} + +void +remote_subscription::remove_client(const client_t _client) { + std::lock_guard<std::mutex> its_lock(mutex_); + clients_.erase(_client); +} + +remote_subscription_state_e +remote_subscription::get_client_state(const client_t _client) const { + std::lock_guard<std::mutex> its_lock(mutex_); + auto found_client = clients_.find(_client); + if (found_client != clients_.end()) { + return found_client->second.first; + } + return remote_subscription_state_e::SUBSCRIPTION_UNKNOWN; +} + +void +remote_subscription::set_client_state(const client_t _client, + remote_subscription_state_e _state) { + std::lock_guard<std::mutex> its_lock(mutex_); + auto found_item = clients_.find(_client); + if (found_item != clients_.end()) { + found_item->second.first = _state; + if (found_item->second.second == std::chrono::steady_clock::time_point() + && (_state == remote_subscription_state_e::SUBSCRIPTION_ACKED + || _state == remote_subscription_state_e::SUBSCRIPTION_NACKED)) { + found_item->second.second = std::chrono::steady_clock::now() + + std::chrono::seconds(ttl_); + } + } +} + +void +remote_subscription::set_all_client_states(remote_subscription_state_e _state) { + std::lock_guard<std::mutex> its_lock(mutex_); + for (auto &its_item : clients_) + its_item.second.first = _state; +} + +std::shared_ptr<endpoint_definition> +remote_subscription::get_subscriber() const { + return subscriber_; +} + +void +remote_subscription::set_subscriber( + const std::shared_ptr<endpoint_definition> &_subscriber) { + subscriber_ = _subscriber; +} + +std::shared_ptr<endpoint_definition> +remote_subscription::get_reliable() const { + return reliable_; +} + +void +remote_subscription::set_reliable( + const std::shared_ptr<endpoint_definition> &_reliable) { + reliable_ = _reliable; +} + +std::shared_ptr<endpoint_definition> +remote_subscription::get_unreliable() const { + return unreliable_; +} + +void +remote_subscription::set_unreliable( + const std::shared_ptr<endpoint_definition> &_unreliable) { + unreliable_ = _unreliable; +} + +bool +remote_subscription::is_pending() const { + std::lock_guard<std::mutex> its_lock(mutex_); + for (auto its_client : clients_) { + if (its_client.second.first + == remote_subscription_state_e::SUBSCRIPTION_PENDING) { + return true; + } + } + return false; +} + +bool +remote_subscription::is_acknowledged() const { + std::lock_guard<std::mutex> its_lock(mutex_); + for (auto its_client : clients_) { + if (its_client.second.first + != remote_subscription_state_e::SUBSCRIPTION_ACKED) { + return false; + } + } + return true; +} + +std::chrono::steady_clock::time_point +remote_subscription::get_expiration(const client_t _client) const { + std::lock_guard<std::mutex> its_lock(mutex_); + auto found_client = clients_.find(_client); + if (found_client != clients_.end()) { + return found_client->second.second; + } + return std::chrono::steady_clock::now(); +} + +std::set<client_t> +remote_subscription::update(const std::set<client_t> &_clients, + const std::chrono::steady_clock::time_point &_timepoint, + const bool _is_subscribe) { + std::set<client_t> its_changed; + + std::lock_guard<std::mutex> its_lock(mutex_); + for (const auto &its_client : _clients) { + auto found_client = clients_.find(its_client); + if (_is_subscribe) { + if (found_client != clients_.end()) { + found_client->second.second = _timepoint; + } else { + its_changed.insert(its_client); + } + } else { + if (found_client != clients_.end()) { + its_changed.insert(its_client); + } + } + } + + for (const auto &its_client : its_changed) { + if (_is_subscribe) { + clients_[its_client] = std::make_pair( + remote_subscription_state_e::SUBSCRIPTION_PENDING, _timepoint); + } else { + clients_.erase(its_client); + } + } + + return its_changed; +} + +std::shared_ptr<remote_subscription> +remote_subscription::get_parent() const { + return parent_.lock(); +} + +void +remote_subscription::set_parent( + const std::shared_ptr<remote_subscription> &_parent) { + parent_ = _parent; +} + +std::uint32_t +remote_subscription::get_answers() const { + return answers_; +} + +void +remote_subscription::set_answers(const std::uint32_t _answers) { + answers_ = _answers; +} + +bool +remote_subscription::get_ip_address(boost::asio::ip::address &_address) const { + if (reliable_) { + _address = reliable_->get_address(); + return true; + } + else if (unreliable_) { + _address = unreliable_->get_address(); + return true; + } + return false; +} + +bool remote_subscription::is_expired() const { + return this->final_destination_.load(std::memory_order_acquire) == destiny::expire; +} + +void remote_subscription::set_expired() { + this->final_destination_.store(destiny::expire, std::memory_order_release); +} + +bool remote_subscription::is_forwarded() const { + return this->final_destination_.load(std::memory_order_acquire) == destiny::forward; +} + +void remote_subscription::set_forwarded() { + this->final_destination_.store(destiny::forward, std::memory_order_release); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_base.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_base.cpp new file mode 100644 index 00000000000..a9438ef4b7e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_base.cpp @@ -0,0 +1,1735 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/routing_manager_base.hpp" +#include "../../configuration/include/debounce_filter_impl.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +routing_manager_base::routing_manager_base(routing_manager_host *_host) : + host_(_host), + io_(host_->get_io()), + configuration_(host_->get_configuration()), + debounce_timer(host_->get_io()), + routing_state_(routing_state_e::RS_UNKNOWN) +#ifdef USE_DLT + , tc_(trace::connector_impl::get()) +#endif +{ + const std::size_t its_max = configuration_->get_io_thread_count(host_->get_name()); + const uint32_t its_buffer_shrink_threshold = + configuration_->get_buffer_shrink_threshold(); + + for (std::size_t i = 0; i < its_max; ++i) { + serializers_.push( + std::make_shared<serializer>(its_buffer_shrink_threshold)); + deserializers_.push( + std::make_shared<deserializer>(its_buffer_shrink_threshold)); + } + + if (!configuration_->is_local_routing()) { + auto its_routing_address = configuration_->get_routing_host_address(); + auto its_routing_port = configuration_->get_routing_host_port(); + if (!its_routing_address.is_unspecified() && !its_routing_address.is_multicast()) { + add_guest(VSOMEIP_ROUTING_CLIENT, its_routing_address, its_routing_port); + } + } +} + +void routing_manager_base::debounce_timeout_update_cbk( + const boost::system::error_code& _error, const std::shared_ptr<vsomeip_v3::event>& _event, + client_t _client, const std::shared_ptr<debounce_filter_impl_t>& _filter) { + if (!_error) { + if (!_event) { + std::lock_guard<std::mutex> its_lock(debounce_mutex_); + if (debounce_clients_.size() > 0) { + debounce_timer.expires_from_now( + std::chrono::duration_cast<std::chrono::milliseconds>( + debounce_clients_.begin()->first + - std::chrono::steady_clock::now())); + debounce_timer.async_wait(std::get<2>(debounce_clients_.begin()->second)); + } + return; + } + + // _event->get_subscribers() cannot be locked by debounce_mutex_, because it can lead to + // Lock inversion with remove_subscribes and its eventgroup_mutex! + auto its_subscribers = _event->get_subscribers(); + + bool notify_client {false}; + { + std::lock_guard<std::mutex> its_lock(debounce_mutex_); + if (its_subscribers.find(_client) != its_subscribers.end() && _filter) { + bool is_elapsed {false}; + auto its_current = std::chrono::steady_clock::now(); + + int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - _filter->last_forwarded_) + .count(); + is_elapsed = + (_filter->last_forwarded_ == std::chrono::steady_clock::time_point::max() + || elapsed >= _filter->interval_); + + auto debounce_client = debounce_clients_.begin(); + auto event_id = std::get<3>(debounce_client->second); + bool has_update = std::get<1>(debounce_client->second); + if (is_elapsed) { + if (std::get<0>(debounce_client->second) == _client && has_update) { + notify_client = true; + has_update = false; + } + elapsed = 0; + } + + debounce_clients_.erase(debounce_client); + + auto timeout = std::chrono::steady_clock::now() + + std::chrono::milliseconds(_filter->interval_ - elapsed); + debounce_clients_.emplace( + timeout, + std::make_tuple( + _client, has_update, + std::bind(&routing_manager_base::debounce_timeout_update_cbk, + shared_from_this(), std::placeholders::_1, _event, + _client, _filter), + event_id)); + } + + if (debounce_clients_.size() > 0) { + debounce_timer.expires_from_now( + std::chrono::duration_cast<std::chrono::milliseconds>( + debounce_clients_.begin()->first + - std::chrono::steady_clock::now())); + debounce_timer.async_wait(std::get<2>(debounce_clients_.begin()->second)); + } + } // its_lock(debounce_mutex_) + + // _event->notify_one cannot be locked by debounce_mutex_, because it can lead to + // Lock inversion with update_and_get_filtered_subscribers and its mutex_! + if (notify_client) { + _event->notify_one(_client, false); + } + } +} + +void routing_manager_base::register_debounce(const std::shared_ptr<debounce_filter_impl_t> &_filter, client_t _client, const std::shared_ptr<vsomeip_v3::event> &_event) { + if (_filter->send_current_value_after_ == true) { + std::lock_guard<std::mutex> its_lock(debounce_mutex_); + auto sec = std::chrono::milliseconds(_filter->interval_); + auto timeout = std::chrono::steady_clock::now() + sec; + + auto elem = debounce_clients_.emplace(timeout, std::make_tuple(_client, false, std::bind(&routing_manager_base::debounce_timeout_update_cbk, shared_from_this(), + std::placeholders::_1, _event, _client, _filter), _event->get_event())); + + if (elem == debounce_clients_.begin()) { + debounce_timer.cancel(); + debounce_timer.expires_from_now(sec); + debounce_timer.async_wait(std::get<2>(elem->second)); + } + } +} + +void routing_manager_base::remove_debounce(client_t _client, event_t _event) { + std::vector<std::chrono::steady_clock::time_point> temp_client_vector; + + std::lock_guard<std::mutex> its_lock(debounce_mutex_); + for (auto &debounce_client: debounce_clients_) { + if ((std::get<0>(debounce_client.second) == _client) && (std::get<3>(debounce_client.second) == _event)) { + temp_client_vector.push_back(debounce_client.first); + } + } + for (auto &elem: temp_client_vector) { + debounce_clients_.erase(elem); + } +} + +void routing_manager_base::update_debounce_clients(const std::set<client_t> &_clients, event_t _event) { + std::lock_guard<std::mutex> its_lock(debounce_mutex_); + for (auto& debounce_client : debounce_clients_) { + if (_event == std::get<3>(debounce_client.second)) { + std::get<1>(debounce_client.second) = true; + for (auto s : _clients) { + if (std::get<0>(debounce_client.second) == s) { + std::get<1>(debounce_client.second) = false; + } + } + } + } +} + +boost::asio::io_context &routing_manager_base::get_io() { + + return io_; +} + +client_t routing_manager_base::get_client() const { + + return host_->get_client(); +} + +void routing_manager_base::set_client(const client_t &_client) { + + host_->set_client(_client); +} + +session_t routing_manager_base::get_session(bool _is_request) { + return host_->get_session(_is_request); +} + +const vsomeip_sec_client_t *routing_manager_base::get_sec_client() const { + + return host_->get_sec_client(); +} + +void routing_manager_base::set_sec_client_port(port_t _port) { + + host_->set_sec_client_port(_port); +} + +std::string routing_manager_base::get_client_host() const { + std::lock_guard<std::mutex> its_env_lock(env_mutex_); + return env_; +} + +void routing_manager_base::set_client_host(const std::string &_client_host) { + + std::lock_guard<std::mutex> its_env_lock(env_mutex_); + env_ = _client_host; +} + +bool routing_manager_base::is_routing_manager() const { + return false; +} + +void routing_manager_base::init(const std::shared_ptr<endpoint_manager_base>& _endpoint_manager) { + ep_mgr_ = _endpoint_manager; +} + +bool routing_manager_base::offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + (void)_client; + + // Remote route (incoming only) + auto its_info = find_service(_service, _instance); + if (its_info) { + if (!its_info->is_local()) { + return false; + } else if (its_info->get_major() == _major + && its_info->get_minor() == _minor) { + its_info->set_ttl(DEFAULT_TTL); + } else { + VSOMEIP_ERROR << "rm_base::offer_service service property mismatch (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << ":" + << std::dec + << static_cast<std::uint32_t>(its_info->get_major()) << ":" + << its_info->get_minor() << "] passed: " + << static_cast<std::uint32_t>(_major) << ":" + << _minor; + return false; + } + } else { + its_info = create_service_info(_service, _instance, _major, _minor, + DEFAULT_TTL, true); + } + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + // Set major version for all registered events of this service and instance + const auto found_service = events_.find(_service); + if (found_service != events_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &j : found_instance->second) { + j.second->set_version(_major); + } + } + } + } + return true; +} + +void routing_manager_base::stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + (void)_client; + (void)_major; + (void)_minor; + + std::map<event_t, std::shared_ptr<event> > events; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + events[e.first] = e.second; + + } + } + } + for (auto &e : events) { + e.second->unset_payload(); + e.second->clear_subscribers(); + } +} + +void routing_manager_base::request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + auto its_info = find_service(_service, _instance); + if (its_info) { + if ((_major == its_info->get_major() + || DEFAULT_MAJOR == its_info->get_major() + || ANY_MAJOR == _major) + && (_minor <= its_info->get_minor() + || DEFAULT_MINOR == its_info->get_minor() + || _minor == ANY_MINOR)) { + its_info->add_client(_client); + } else { + VSOMEIP_ERROR << "rm_base::request_service service property mismatch (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << ":" + << std::dec + << static_cast<std::uint32_t>(its_info->get_major()) << ":" + << its_info->get_minor() << "] passed: " + << static_cast<std::uint32_t>(_major) << ":" + << _minor; + } + } +} + +void routing_manager_base::release_service(client_t _client, + service_t _service, instance_t _instance) { + auto its_info = find_service(_service, _instance); + if (its_info) { + its_info->remove_client(_client); + } + { + std::lock_guard<std::mutex> its_service_guard(local_services_mutex_); + auto found_service = local_services_history_.find(_service); + if (found_service != local_services_history_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + found_service->second.erase(_instance); + if (found_service->second.empty()) { + local_services_history_.erase(_service); + } + } + } + } +} + +void routing_manager_base::register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, + const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + std::lock_guard<std::mutex> its_registration_lock(event_registration_mutex_); + + auto determine_event_reliability = [this, &_service, &_instance, + &_notifier, &_reliability]() { + reliability_type_e its_reliability = + configuration_->get_event_reliability(_service, _instance, _notifier); + if (its_reliability != reliability_type_e::RT_UNKNOWN) { + // event was explicitly configured -> overwrite value passed via API + return its_reliability; + } else if (_reliability != reliability_type_e::RT_UNKNOWN) { + // use value provided via API + return _reliability; + } else { // automatic mode, user service' reliability + return configuration_->get_service_reliability(_service, _instance); + } + }; + + std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier); + bool transfer_subscriptions_from_any_event(false); + if (its_event) { + if (!its_event->is_cache_placeholder()) { + if (_type == its_event->get_type() + || its_event->get_type() == event_type_e::ET_UNKNOWN) { + if (_is_provided) { + its_event->set_provided(true); + its_event->set_reliability(determine_event_reliability()); + } + if (_is_shadow && _is_provided) { + its_event->set_shadow(_is_shadow); + } + if (_client == host_->get_client() && _is_provided) { + its_event->set_shadow(false); + its_event->set_update_on_change(_update_on_change); + } + for (auto eg : _eventgroups) { + its_event->add_eventgroup(eg); + } + transfer_subscriptions_from_any_event = true; + } else { +#ifdef VSOMEIP_ENABLE_COMPAT + if (!(its_event->get_type() == event_type_e::ET_SELECTIVE_EVENT + && _type == event_type_e::ET_EVENT)) +#endif + VSOMEIP_ERROR << "Event registration update failed. " + "Specified arguments do not match existing registration."; + } + } else { + // the found event was a placeholder for caching. + // update it with the real values + if (_type != event_type_e::ET_FIELD) { + // don't cache payload for non-fields + its_event->unset_payload(true); + } + if (_is_shadow && _is_provided) { + its_event->set_shadow(_is_shadow); + } + if (_client == host_->get_client() && _is_provided) { + its_event->set_shadow(false); + its_event->set_update_on_change(_update_on_change); + } + its_event->set_type(_type); + its_event->set_reliability(determine_event_reliability()); + its_event->set_provided(_is_provided); + its_event->set_cache_placeholder(false); + std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance); + if (its_service) { + its_event->set_version(its_service->get_major()); + } + if (_eventgroups.size() == 0) { // No eventgroup specified + std::set<eventgroup_t> its_eventgroups; + its_eventgroups.insert(_notifier); + its_event->set_eventgroups(its_eventgroups); + } else { + for (auto eg : _eventgroups) { + its_event->add_eventgroup(eg); + } + } + + its_event->set_epsilon_change_function(_epsilon_change_func); + its_event->set_change_resets_cycle(_change_resets_cycle); + its_event->set_update_cycle(_cycle); + } + } else { + its_event = std::make_shared<event>(this, _is_shadow); + its_event->set_service(_service); + its_event->set_instance(_instance); + its_event->set_event(_notifier); + its_event->set_type(_type); + its_event->set_reliability(determine_event_reliability()); + its_event->set_provided(_is_provided); + its_event->set_cache_placeholder(_is_cache_placeholder); + std::shared_ptr<serviceinfo> its_service = find_service(_service, _instance); + if (its_service) { + its_event->set_version(its_service->get_major()); + } + + if (_eventgroups.size() == 0) { // No eventgroup specified + std::set<eventgroup_t> its_eventgroups; + its_eventgroups.insert(_notifier); + its_event->set_eventgroups(its_eventgroups); + } else { + its_event->set_eventgroups(_eventgroups); + } + + if ((_is_shadow || is_routing_manager()) && !_epsilon_change_func) { + std::shared_ptr<debounce_filter_impl_t> its_debounce + = configuration_->get_debounce(host_->get_name(), _service, _instance, _notifier); + if (its_debounce) { + std::stringstream its_debounce_parameters; + its_debounce_parameters << "(on_change=" + << (its_debounce->on_change_ ? "true" : "false") + << ", ignore=[ "; + for (auto i : its_debounce->ignore_) + its_debounce_parameters << "(" << std::dec << i.first + << ", " << std::hex << (int)i.second << ") "; + its_debounce_parameters << "], interval=" + << std::dec << its_debounce->interval_ << ")"; + + VSOMEIP_WARNING << "Using debounce configuration for " + << " SOME/IP event " + << std::hex << std::setw(4) << std::setfill('0') + << _service << "." + << std::hex << std::setw(4) << std::setfill('0') + << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') + << _notifier << "." + << " Debounce parameters: " + << its_debounce_parameters.str(); + + _epsilon_change_func = [its_debounce]( + const std::shared_ptr<payload> &_old, + const std::shared_ptr<payload> &_new) { + + bool is_changed(false), is_elapsed(false); + + // Check whether we should forward because of changed data + if (its_debounce->on_change_) { + length_t its_min_length, its_max_length; + + if (_old->get_length() < _new->get_length()) { + its_min_length = _old->get_length(); + its_max_length = _new->get_length(); + } else { + its_min_length = _new->get_length(); + its_max_length = _old->get_length(); + } + + // Check whether all additional bytes (if any) are excluded + for (length_t i = its_min_length; i < its_max_length; i++) { + auto j = its_debounce->ignore_.find(i); + // A change is detected when an additional byte is not + // excluded at all or if its exclusion does not cover all + // bits + if (j == its_debounce->ignore_.end() || j->second != 0xFF) { + is_changed = true; + break; + } + } + + if (!is_changed) { + const byte_t *its_old = _old->get_data(); + const byte_t *its_new = _new->get_data(); + for (length_t i = 0; i < its_min_length; i++) { + auto j = its_debounce->ignore_.find(i); + if (j == its_debounce->ignore_.end()) { + if (its_old[i] != its_new[i]) { + is_changed = true; + break; + } + } else if (j->second != 0xFF) { + if ((its_old[i] & ~(j->second)) != (its_new[i] & ~(j->second))) { + is_changed = true; + break; + } + } + } + } + } + + if (its_debounce->interval_ > -1) { + // Check whether we should forward because of the elapsed time since + // we did last time + std::chrono::steady_clock::time_point its_current + = std::chrono::steady_clock::now(); + int64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( + its_current - its_debounce->last_forwarded_).count(); + is_elapsed = (its_debounce->last_forwarded_ == std::chrono::steady_clock::time_point::max() + || elapsed >= its_debounce->interval_); + if (is_elapsed || (is_changed && its_debounce->on_change_resets_interval_)) + its_debounce->last_forwarded_ = its_current; + } + return (is_changed || is_elapsed); + }; + + // Create a new callback for this client if filter interval is used + register_debounce(its_debounce, _client, its_event); + } else { + if (_is_shadow || !is_routing_manager()) { + _epsilon_change_func = [](const std::shared_ptr<payload> &_old, + const std::shared_ptr<payload> &_new) { + (void)_old; + (void)_new; + return true; + }; + } + } + } + + its_event->set_epsilon_change_function(_epsilon_change_func); + its_event->set_change_resets_cycle(_change_resets_cycle); + its_event->set_update_cycle(_cycle); + its_event->set_update_on_change(_update_on_change); + + if (_is_provided) { + transfer_subscriptions_from_any_event = true; + } + } + + if (transfer_subscriptions_from_any_event) { + // check if someone subscribed to ANY_EVENT and the subscription + // was stored in the cache placeholder. Move the subscribers + // into new event + std::shared_ptr<event> its_any_event = + find_event(_service, _instance, ANY_EVENT); + if (its_any_event) { + std::set<eventgroup_t> any_events_eventgroups = + its_any_event->get_eventgroups(); + for (eventgroup_t eventgroup : _eventgroups) { + auto found_eg = any_events_eventgroups.find(eventgroup); + if (found_eg != any_events_eventgroups.end()) { + std::set<client_t> its_any_event_subscribers = + its_any_event->get_subscribers(eventgroup); + for (const client_t subscriber : its_any_event_subscribers) { + its_event->add_subscriber(eventgroup, nullptr, subscriber, true); + } + } + } + } + } + if(!_is_cache_placeholder) { + its_event->add_ref(_client, _is_provided); + } + + for (auto eg : _eventgroups) { + std::shared_ptr<eventgroupinfo> its_eventgroupinfo + = find_eventgroup(_service, _instance, eg); + if (!its_eventgroupinfo) { + its_eventgroupinfo = std::make_shared<eventgroupinfo>(); + its_eventgroupinfo->set_service(_service); + its_eventgroupinfo->set_instance(_instance); + its_eventgroupinfo->set_eventgroup(eg); + its_eventgroupinfo->set_max_remote_subscribers( + configuration_->get_max_remote_subscribers()); + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + eventgroups_[_service][_instance][eg] = its_eventgroupinfo; + } + its_eventgroupinfo->add_event(its_event); + } + + std::lock_guard<std::mutex> its_lock(events_mutex_); + events_[_service][_instance][_notifier] = its_event; +} + +void routing_manager_base::unregister_event(client_t _client, service_t _service, instance_t _instance, + event_t _event, bool _is_provided) { + (void)_client; + std::shared_ptr<event> its_unrefed_event; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto found_service = events_.find(_service); + if (found_service != events_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + auto its_event = found_event->second; + its_event->remove_ref(_client, _is_provided); + if (!its_event->has_ref()) { + its_unrefed_event = its_event; + found_instance->second.erase(found_event); + } else if (_is_provided) { + its_event->set_provided(false); + } + } + } + } + } + if (its_unrefed_event) { + auto its_eventgroups = its_unrefed_event->get_eventgroups(); + for (auto eg : its_eventgroups) { + std::shared_ptr<eventgroupinfo> its_eventgroup_info + = find_eventgroup(_service, _instance, eg); + if (its_eventgroup_info) { + its_eventgroup_info->remove_event(its_unrefed_event); + if (0 == its_eventgroup_info->get_events().size()) { + remove_eventgroup_info(_service, _instance, eg); + } + } + } + } +} + +std::set<std::shared_ptr<event>> routing_manager_base::find_events( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + std::set<std::shared_ptr<event> > its_events; + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + return found_eventgroup->second->get_events(); + } + } + } + return its_events; +} + +std::vector<event_t> routing_manager_base::find_events( + service_t _service, instance_t _instance) const { + std::vector<event_t> its_events; + std::lock_guard<std::mutex> its_lock(events_mutex_); + const auto found_service = events_.find(_service); + if (found_service != events_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& e : found_instance->second) { + its_events.push_back(e.first); + } + } + } + return its_events; +} + +bool routing_manager_base::is_response_allowed(client_t _sender, service_t _service, + instance_t _instance, method_t _method) { + + if (!configuration_->is_security_enabled() + || !configuration_->is_local_routing()) { + return true; + } + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + if (_sender == find_local_client_unlocked(_service, _instance)) { + // sender is still offering the service + return true; + } + + auto found_service = local_services_history_.find(_service); + if (found_service != local_services_history_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_client = found_instance->second.find(_sender); + if (found_client != found_instance->second.end()) { + // sender was offering the service and is still connected + return true; + } + } + } + } + + // service is now offered by another client + // or service is not offered at all + std::string security_mode_text = "!"; + if (!configuration_->is_security_audit()) { + security_mode_text = ", but will be allowed due to audit mode is active!"; + } + + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_base::is_response_allowed: " + << "received a response from client 0x" << _sender + << " which does not offer service/instance/method " + << _service << "/" << _instance << "/" << _method + << security_mode_text; + + return !configuration_->is_security_audit(); +} + +bool routing_manager_base::is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + + bool is_allowed(true); + + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto& e : its_eventgroup->get_events()) { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, _service, _instance, e->get_event())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << _client << " : routing_manager_base::is_subscribe_to_any_event_allowed: " + << "subscribes to service/instance/event " + << _service << "/" << _instance << "/" << e->get_event() + << " which violates the security policy!"; + is_allowed = false; + break; + } + } + } + + return is_allowed; +} + +void routing_manager_base::add_known_client(client_t _client, const std::string &_client_host) { +#if !defined(VSOMEIP_DISABLE_SECURITY) && (defined(__linux__) || defined(ANDROID)) + std::lock_guard<std::mutex> lazy_lock(add_known_client_mutex_); + if (configuration_->is_security_enabled() && !configuration_->is_security_external()) { + //Ignore if we have already loaded the policy extension + policy_manager_impl::policy_loaded_e policy_loaded + = configuration_->get_policy_manager()->is_policy_extension_loaded(_client_host); + + if (policy_loaded == policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_NOT_LOADED) + { + if (configuration_->lazy_load_security(_client_host)) { + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << _client_host + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } + } else if (policy_loaded == policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT) { + if (configuration_->lazy_load_security(_client_host)) + { + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << _client_host + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } else if (configuration_->lazy_load_security(get_client_host())) { //necessary for lazy loading from inside android container + VSOMEIP_INFO << __func__ << " vSomeIP Security: Loaded security policies for host: " + << get_client_host() + << " at UID/GID: " << std::dec << getuid() << "/" << getgid(); + } + } + } +#endif + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + known_clients_[_client] = _client_host; +} + +void routing_manager_base::subscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) { + + (void)_major; + (void)_sec_client; + + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription(_service, _instance, _eventgroup, + _event, _filter, _client, &its_already_subscribed_events); + if (inserted) { + notify_one_current_value(_client, _service, _instance, _eventgroup, + _event, its_already_subscribed_events); + } +} + +void routing_manager_base::unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) { + + (void)_sec_client; + + if (_event != ANY_EVENT) { + auto its_event = find_event(_service, _instance, _event); + if (its_event) { + its_event->remove_subscriber(_eventgroup, _client); + } + } else { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto &e : its_eventgroup->get_events()) { + if (e) + e->remove_subscriber(_eventgroup, _client); + } + } + } +} + +void routing_manager_base::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force) { + + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + its_event->set_payload(_payload, _force); + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } +} + +void routing_manager_base::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force +#ifdef VSOMEIP_ENABLE_COMPAT + , bool _remote_subscriber +#endif + ) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + // Event is valid for service/instance + bool found_eventgroup(false); + bool already_subscribed(false); +#ifdef VSOMEIP_ENABLE_COMPAT + eventgroup_t valid_group = 0; + subscription_state_e its_subscription_state(subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED); +#endif + // Iterate over all groups of the event to ensure at least + // one valid eventgroup for service/instance exists. + for (auto its_group : its_event->get_eventgroups()) { + auto its_eventgroup = find_eventgroup(_service, _instance, its_group); + if (its_eventgroup) { + // Eventgroup is valid for service/instance + found_eventgroup = true; +#ifdef VSOMEIP_ENABLE_COMPAT + valid_group = its_group; + its_subscription_state = get_incoming_subscription_state(_client, _service, + _instance, valid_group, _event); +#endif + if (ep_mgr_->find_local(_client)) { + already_subscribed = its_event->has_subscriber(its_group, _client); +#ifdef VSOMEIP_ENABLE_COMPAT + } else if (subscription_state_e::IS_SUBSCRIBING != its_subscription_state + || _remote_subscriber) { + // Remotes always needs to be marked as subscribed here if they are not currently subscribing +#else + } else { + // Remotes always needs to be marked as subscribed here +#endif + already_subscribed = true; + } + break; + } + } + if (found_eventgroup) { + if (already_subscribed) { + its_event->set_payload(_payload, _client, _force); + } +#ifdef VSOMEIP_ENABLE_COMPAT + else { + // cache notification if subscription is in progress + if (subscription_state_e::IS_SUBSCRIBING == its_subscription_state) { + VSOMEIP_INFO << "routing_manager_base::notify_one(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << valid_group << "." + << std::setw(4) << _event << "]" + << " insert pending notification!"; + std::shared_ptr<message> its_notification + = runtime::get()->create_notification(); + its_notification->set_service(_service); + its_notification->set_instance(_instance); + its_notification->set_method(_event); + its_notification->set_payload(_payload); + auto service_info = find_service(_service, _instance); + if (service_info) { + its_notification->set_interface_version(service_info->get_major()); + } + { + std::lock_guard<std::recursive_mutex> its_lock(pending_notify_ones_mutex_); + pending_notify_ones_[_service][_instance][valid_group] = its_notification; + } + } + } +#endif + } + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } +} + +#ifdef VSOMEIP_ENABLE_COMPAT +void routing_manager_base::send_pending_notify_ones(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client, bool _remote_subscriber) { + std::lock_guard<std::recursive_mutex> its_lock(pending_notify_ones_mutex_); + auto its_service = pending_notify_ones_.find(_service); + if (its_service != pending_notify_ones_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + VSOMEIP_INFO << "routing_manager_base::send_pending_notify_ones(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << its_group->second->get_method() << "]"; + + notify_one(_service, _instance, its_group->second->get_method(), + its_group->second->get_payload(), _client, false, _remote_subscriber); + its_instance->second.erase(_eventgroup); + } + } + } +} +#endif + +void routing_manager_base::unset_all_eventpayloads(service_t _service, + instance_t _instance) { + std::set<std::shared_ptr<event>> its_events; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + const auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &eventgroupinfo : found_instance->second) { + for (const auto &event : eventgroupinfo.second->get_events()) { + its_events.insert(event); + } + } + } + } + } + for (const auto &e : its_events) { + e->unset_payload(true); + } +} + +void routing_manager_base::unset_all_eventpayloads(service_t _service, + instance_t _instance, + eventgroup_t _eventgroup) { + std::set<std::shared_ptr<event>> its_events; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + const auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + const auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + for (const auto &event : found_eventgroup->second->get_events()) { + its_events.insert(event); + } + } + } + } + } + for (const auto &e : its_events) { + e->unset_payload(true); + } +} + +void routing_manager_base::notify_one_current_value( + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + const std::set<event_t> &_events_to_exclude) { + if (_event != ANY_EVENT) { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event && its_event->is_field()) + its_event->notify_one(_client, false); + } else { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + std::set<std::shared_ptr<event> > its_events = its_eventgroup->get_events(); + for (const auto &e : its_events) { + if (e->is_field() + && _events_to_exclude.find(e->get_event()) + == _events_to_exclude.end()) { + e->notify_one(_client, false); + } + } + } + } +} + +bool routing_manager_base::send(client_t _client, + std::shared_ptr<message> _message, bool _force) { + bool is_sent(false); + if (utility::is_request(_message->get_message_type())) { + _message->set_client(_client); + } + + std::shared_ptr<serializer> its_serializer(get_serializer()); + if (its_serializer->serialize(_message.get())) { + is_sent = send(_client, its_serializer->get_data(), + its_serializer->get_size(), _message->get_instance(), + _message->is_reliable(), get_client(), get_sec_client(), + 0, false, _force); + its_serializer->reset(); + put_serializer(its_serializer); + } else { + VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; + } + return is_sent; +} + +// ********************************* PROTECTED ************************************** +std::shared_ptr<serviceinfo> routing_manager_base::create_service_info( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, bool _is_local_service) { + std::shared_ptr<serviceinfo> its_info = + std::make_shared<serviceinfo>(_service, _instance, + _major, _minor, _ttl, _is_local_service); + { + std::lock_guard<std::mutex> its_lock(services_mutex_); + services_[_service][_instance] = its_info; + } + if (!_is_local_service) { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + services_remote_[_service][_instance] = its_info; + } + return its_info; +} + +std::shared_ptr<serviceinfo> routing_manager_base::find_service( + service_t _service, instance_t _instance) const { + std::shared_ptr<serviceinfo> its_info; + std::lock_guard<std::mutex> its_lock(services_mutex_); + auto found_service = services_.find(_service); + if (found_service != services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + its_info = found_instance->second; + } + } + return its_info; +} + +void routing_manager_base::clear_service_info(service_t _service, instance_t _instance, + bool _reliable) { + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if (!its_info) { + return; + } + + bool deleted_instance(false); + bool deleted_service(false); + { + std::lock_guard<std::mutex> its_lock(services_mutex_); + + // Clear service_info and service_group + std::shared_ptr<endpoint> its_empty_endpoint; + if (!its_info->get_endpoint(!_reliable)) { + if (1 >= services_[_service].size()) { + services_.erase(_service); + deleted_service = true; + } else { + services_[_service].erase(_instance); + deleted_instance = true; + } + } else { + its_info->set_endpoint(its_empty_endpoint, _reliable); + } + } + + if ((deleted_instance || deleted_service) && !its_info->is_local()) { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + if (deleted_service) { + services_remote_.erase(_service); + } else if (deleted_instance) { + services_remote_[_service].erase(_instance); + } + } +} + +services_t routing_manager_base::get_services() const { + std::lock_guard<std::mutex> its_lock(services_mutex_); + return services_; +} + +services_t routing_manager_base::get_services_remote() const { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + return services_remote_; +} + +bool routing_manager_base::is_available(service_t _service, instance_t _instance, + major_version_t _major) { + bool available(false); + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + if (_instance == ANY_INSTANCE) { + return true; + } + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + if (_major == ANY_MAJOR) { + return true; + } + if (std::get<0>(its_instance->second) == _major) { + available = true; + } + } + } + return available; +} + +std::set<client_t> routing_manager_base::find_local_clients(service_t _service, instance_t _instance) { + std::set<client_t> its_clients; + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + if (_instance == ANY_INSTANCE) { + for (auto its_instance : its_service->second) { + its_clients.insert(std::get<2>(its_instance.second)); + } + } else { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_clients.insert(std::get<2>(its_instance->second)); + } + } + } + return its_clients; +} + +client_t routing_manager_base::find_local_client(service_t _service, + instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + return find_local_client_unlocked(_service, _instance); +} + +client_t routing_manager_base::find_local_client_unlocked(service_t _service, + instance_t _instance) const { + client_t its_client(VSOMEIP_ROUTING_CLIENT); + auto its_service = local_services_.find(_service); + if (its_service != local_services_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + its_client = std::get<2>(its_instance->second); + } + } + return its_client; +} + +void routing_manager_base::remove_local(client_t _client, bool _remove_uid) { + remove_local(_client, get_subscriptions(_client), _remove_uid); +} + +void routing_manager_base::remove_local(client_t _client, + const std::set<std::tuple<service_t, instance_t, eventgroup_t>>& _subscribed_eventgroups, + bool _remove_sec_client) { + + vsomeip_sec_client_t its_sec_client; + configuration_->get_policy_manager()->get_client_to_sec_client_mapping(_client, its_sec_client); + + if (_remove_sec_client) { + configuration_->get_policy_manager()->remove_client_to_sec_client_mapping(_client); + } + for (auto its_subscription : _subscribed_eventgroups) { + host_->on_subscription(std::get<0>(its_subscription), std::get<1>(its_subscription), + std::get<2>(its_subscription), _client, + &its_sec_client, get_env(_client), + false, [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + routing_manager_base::unsubscribe(_client, &its_sec_client, std::get<0>(its_subscription), + std::get<1>(its_subscription), std::get<2>(its_subscription), ANY_EVENT); + } + ep_mgr_->remove_local(_client); + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + // Finally remove all services that are implemented by the client. + std::set<std::pair<service_t, instance_t>> its_services; + for (const auto& s : local_services_) { + for (const auto& i : s.second) { + if (std::get<2>(i.second) == _client) { + its_services.insert({ s.first, i.first }); + host_->on_availability(s.first, i.first, availability_state_e::AS_UNAVAILABLE, + std::get<0>(i.second), std::get<1>(i.second)); + } + } + } + + for (auto& si : its_services) { + local_services_[si.first].erase(si.second); + if (local_services_[si.first].size() == 0) + local_services_.erase(si.first); + } + + // remove disconnected client from offer service history + std::set<std::tuple<service_t, instance_t, client_t>> its_clients; + for (const auto& s : local_services_history_) { + for (const auto& i : s.second) { + for (const auto& c : i.second) { + if (c == _client) { + its_clients.insert(std::make_tuple(s.first, i.first, c)); + } + } + } + } + + for (auto& sic : its_clients) { + local_services_history_[std::get<0>(sic)][std::get<1>(sic)].erase(std::get<2>(sic)); + if (local_services_history_[std::get<0>(sic)][std::get<1>(sic)].size() == 0) { + local_services_history_.erase(std::get<0>(sic)); + } + } + } +} + +std::shared_ptr<event> routing_manager_base::find_event(service_t _service, + instance_t _instance, event_t _event) const { + std::lock_guard<std::mutex> its_lock(events_mutex_); + std::shared_ptr<event> its_event; + auto find_service = events_.find(_service); + if (find_service != events_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + auto find_event = find_instance->second.find(_event); + if (find_event != find_instance->second.end()) { + its_event = find_event->second; + } + } + } + return its_event; +} + +std::set<std::shared_ptr<eventgroupinfo> > +routing_manager_base::find_eventgroups( + service_t _service, instance_t _instance) const { + + std::set<std::shared_ptr<eventgroupinfo> > its_eventgroups; + + std::lock_guard<std::mutex> its_lock{eventgroups_mutex_}; + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &e : found_instance->second) + its_eventgroups.insert(e.second); + } + } + + return its_eventgroups; +} + +std::shared_ptr<eventgroupinfo> routing_manager_base::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + + std::shared_ptr<eventgroupinfo> its_info(nullptr); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + its_info = found_eventgroup->second; + std::shared_ptr<serviceinfo> its_service_info + = find_service(_service, _instance); + if (its_service_info) { + std::string its_multicast_address; + uint16_t its_multicast_port; + if (configuration_->get_multicast(_service, _instance, + _eventgroup, + its_multicast_address, its_multicast_port)) { + try { + its_info->set_multicast( + boost::asio::ip::address::from_string( + its_multicast_address), + its_multicast_port); + } + catch (...) { + VSOMEIP_ERROR << "Eventgroup [" + << std::hex << std::setw(4) << std::setfill('0') + << _service << "." << _instance << "." << _eventgroup + << "] is configured as multicast, but no valid " + "multicast address is configured!"; + } + } + + // LB: THIS IS STRANGE. A "FIND" - METHOD SHOULD NOT ADD INFORMATION... + its_info->set_major(its_service_info->get_major()); + its_info->set_ttl(its_service_info->get_ttl()); + its_info->set_threshold(configuration_->get_threshold( + _service, _instance, _eventgroup)); + } + } + } + } + return its_info; +} + +void routing_manager_base::remove_eventgroup_info(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + found_instance->second.erase(_eventgroup); + } + } +} + +bool routing_manager_base::send_local_notification(client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _reliable, uint8_t _status_check, bool _force) { +#ifdef USE_DLT + bool has_local(false); +#endif + (void)_client; + bool has_remote(false); + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + + std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); + if (its_event && !its_event->is_shadow()) { + for (auto its_client : its_event->get_filtered_subscribers(_force)) { + + // local + if (its_client == VSOMEIP_ROUTING_CLIENT) { + has_remote = true; + continue; + } +#ifdef USE_DLT + else { + has_local = true; + } +#endif + + std::shared_ptr<endpoint> its_local_target = ep_mgr_->find_local(its_client); + if (its_local_target) { + send_local(its_local_target, its_client, _data, _size, _instance, _reliable, + protocol::id_e::SEND_ID, _status_check); + } + } + } +#ifdef USE_DLT + // Trace the message if a local client but will _not_ be forwarded to the routing manager + if (has_local && !has_remote) { + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif + return has_remote; +} + +bool routing_manager_base::send_local( + std::shared_ptr<endpoint> &_target, client_t _client, + const byte_t *_data, uint32_t _size, instance_t _instance, + bool _reliable, protocol::id_e _command, uint8_t _status_check) const { + + bool has_sent(false); + + protocol::send_command its_command(_command); + its_command.set_client(get_client()); + its_command.set_instance(_instance); + its_command.set_reliable(_reliable); + its_command.set_status(_status_check); + its_command.set_target(_client); + its_command.set_message(std::vector<byte_t>(_data, _data + _size)); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + + return has_sent; +} + +bool routing_manager_base::insert_subscription( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client, std::set<event_t> *_already_subscribed_events) { + + bool is_inserted(false); + if (_event != ANY_EVENT) { // subscribe to specific event + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + is_inserted = its_event->add_subscriber(_eventgroup, _filter, _client, + host_->is_routing()); + } else { + VSOMEIP_WARNING << "routing_manager_base::insert_subscription(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " received subscription for unknown (unrequested / " + << "unoffered) event. Creating placeholder event holding " + << "subscription until event is requested/offered."; + is_inserted = create_placeholder_event_and_subscribe(_service, + _instance, _eventgroup, _event, _filter, _client); + } + } else { // subscribe to all events of the eventgroup + std::shared_ptr<eventgroupinfo> its_eventgroup + = find_eventgroup(_service, _instance, _eventgroup); + bool create_place_holder(false); + if (its_eventgroup) { + std::set<std::shared_ptr<event>> its_events = its_eventgroup->get_events(); + if (!its_events.size()) { + create_place_holder = true; + } else { + for (const auto &e : its_events) { + if (e->is_subscribed(_client)) { + // client is already subscribed to event from eventgroup + // this can happen if events are members of multiple + // eventgroups + _already_subscribed_events->insert(e->get_event()); + } + is_inserted = e->add_subscriber(_eventgroup, _filter, _client, + host_->is_routing()) || is_inserted; + } + } + } else { + create_place_holder = true; + } + if (create_place_holder) { + VSOMEIP_WARNING << "routing_manager_base::insert_subscription(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " received subscription for unknown (unrequested / " + << "unoffered) eventgroup. Creating placeholder event holding " + << "subscription until event is requested/offered."; + is_inserted = create_placeholder_event_and_subscribe(_service, + _instance, _eventgroup, _event, _filter, _client); + } + } + return is_inserted; +} + +std::shared_ptr<serializer> routing_manager_base::get_serializer() { + + std::unique_lock<std::mutex> its_lock(serializer_mutex_); + while (serializers_.empty()) { + VSOMEIP_INFO << __func__ << ": Client " + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << " has no available serializer. Waiting..."; + serializer_condition_.wait(its_lock, [this] { return !serializers_.empty(); } ); + VSOMEIP_INFO << __func__ << ": Client " + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << " now checking for available serializer."; + } + + auto its_serializer = serializers_.front(); + serializers_.pop(); + + return its_serializer; +} + +void routing_manager_base::put_serializer( + const std::shared_ptr<serializer> &_serializer) { + + std::lock_guard<std::mutex> its_lock(serializer_mutex_); + serializers_.push(_serializer); + serializer_condition_.notify_one(); +} + +std::shared_ptr<deserializer> routing_manager_base::get_deserializer() { + + std::unique_lock<std::mutex> its_lock(deserializer_mutex_); + while (deserializers_.empty()) { + VSOMEIP_INFO << std::hex << "client " << get_client() << + "routing_manager_base::get_deserializer ~> all in use!"; + deserializer_condition_.wait(its_lock, [this] { return !deserializers_.empty(); }); + VSOMEIP_INFO << std::hex << "client " << get_client() << + "routing_manager_base::get_deserializer ~> wait finished!"; + } + + auto its_deserializer = deserializers_.front(); + deserializers_.pop(); + + return its_deserializer; +} + +void routing_manager_base::put_deserializer( + const std::shared_ptr<deserializer> &_deserializer) { + + std::lock_guard<std::mutex> its_lock(deserializer_mutex_); + deserializers_.push(_deserializer); + deserializer_condition_.notify_one(); +} + +void routing_manager_base::send_pending_subscriptions(service_t _service, + instance_t _instance, major_version_t _major) { + for (auto &ps : pending_subscriptions_) { + if (ps.service_ == _service && + ps.instance_ == _instance && ps.major_ == _major) { + send_subscribe(get_client(), ps.service_, ps.instance_, + ps.eventgroup_, ps.major_, ps.event_, ps.filter_); + } + } +} + +void routing_manager_base::remove_pending_subscription(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + if (_eventgroup == 0xFFFF) { + for (auto it = pending_subscriptions_.begin(); + it != pending_subscriptions_.end();) { + if (it->service_ == _service + && it->instance_ == _instance) { + it = pending_subscriptions_.erase(it); + } else { + it++; + } + } + } else if (_event == ANY_EVENT) { + for (auto it = pending_subscriptions_.begin(); + it != pending_subscriptions_.end();) { + if (it->service_ == _service + && it->instance_ == _instance + && it->eventgroup_ == _eventgroup) { + it = pending_subscriptions_.erase(it); + } else { + it++; + } + } + } else { + for (auto it = pending_subscriptions_.begin(); + it != pending_subscriptions_.end();) { + if (it->service_ == _service + && it->instance_ == _instance + && it->eventgroup_ == _eventgroup + && it->event_ == _event) { + it = pending_subscriptions_.erase(it); + break; + } else { + it++; + } + } + } +} + +std::set<std::tuple<service_t, instance_t, eventgroup_t>> +routing_manager_base::get_subscriptions(const client_t _client) { + std::set<std::tuple<service_t, instance_t, eventgroup_t>> result; + std::lock_guard<std::mutex> its_lock(events_mutex_); + for (const auto& its_service : events_) { + for (const auto& its_instance : its_service.second) { + for (const auto& its_event : its_instance.second) { + auto its_eventgroups = its_event.second->get_eventgroups(_client); + for (const auto& e : its_eventgroups) { + result.insert(std::make_tuple( + its_service.first, + its_instance.first, + e)); + } + } + } + } + return result; +} + + +void routing_manager_base::clear_shadow_subscriptions(void) { + std::lock_guard<std::mutex> its_lock(events_mutex_); + for (const auto& its_service : events_) { + for (const auto& its_instance : its_service.second) { + for (const auto& its_event : its_instance.second) { + if (its_event.second->is_shadow()) + its_event.second->clear_subscribers(); + } + } + } +} + +bool +routing_manager_base::get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + auto find_guest = guests_.find(_client); + if (find_guest == guests_.end()) + return false; + + _address = find_guest->second.first; + _port = find_guest->second.second; + + return true; +} + +void +routing_manager_base::add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + guests_[_client] = std::make_pair(_address, _port); +} + +void +routing_manager_base::remove_guest(client_t _client) { + + std::lock_guard<std::mutex> its_lock(guests_mutex_); + guests_.erase(_client); +} + +void +routing_manager_base::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + (void)_local_port; + (void)_remote_address; + (void)_remote_port; + // dummy method to implement routing_host interface +} + +routing_state_e +routing_manager_base::get_routing_state() { + return routing_state_; +} + +#ifdef VSOMEIP_ENABLE_COMPAT +void routing_manager_base::set_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, subscription_state_e _state) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + incoming_subscription_state_[_client][_service][_instance][_eventgroup][_event] = _state; +} + +subscription_state_e routing_manager_base::get_incoming_subscription_state(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + const auto its_client = incoming_subscription_state_.find(_client); + if (its_client != incoming_subscription_state_.end()) { + const auto its_service = its_client->second.find(_service); + if (its_service != its_client->second.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + const auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + const auto its_event = its_group->second.find(_event); + if (its_event != its_group->second.end()) { + return its_event->second; + } + // If a specific event was not found, check if there is a remote subscriber to ANY_EVENT + const auto its_any_event = its_group->second.find(ANY_EVENT); + if (its_any_event != its_group->second.end()) { + return its_any_event->second; + } + } + } + } + } + return subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; +} + +void routing_manager_base::erase_incoming_subscription_state(client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscription_state_mutex_); + const auto its_client = incoming_subscription_state_.find(_client); + if (its_client != incoming_subscription_state_.end()) { + const auto its_service = its_client->second.find(_service); + if (its_service != its_client->second.end()) { + const auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + const auto its_group = its_instance->second.find(_eventgroup); + if (its_group != its_instance->second.end()) { + const auto its_event = its_group->second.find(_event); + if (its_event != its_group->second.end()) { + its_group->second.erase(_event); + if (its_group->second.empty()) { + its_instance->second.erase(its_group); + if (its_instance->second.empty()) { + its_service->second.erase(its_instance); + if (its_service->second.empty()) { + its_client->second.erase(its_service); + if (its_client->second.empty()) { + incoming_subscription_state_.erase(its_client); + } + } + } + } + } + } + } + } + } +} +#endif + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_client.cpp new file mode 100644 index 00000000000..e480be63a5e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_client.cpp @@ -0,0 +1,3025 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if __GNUC__ > 11 +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <unistd.h> +#endif + +#include <climits> +#include <forward_list> +#include <future> +#include <iomanip> +#include <mutex> +#include <thread> +#include <unordered_set> + +#include <vsomeip/constants.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/event.hpp" +#include "../include/routing_manager_host.hpp" +#include "../include/routing_manager_client.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/netlink_connector.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/message_impl.hpp" +#include "../../message/include/serializer.hpp" +#include "../../protocol/include/assign_client_command.hpp" +#include "../../protocol/include/assign_client_ack_command.hpp" +#include "../../protocol/include/config_command.hpp" +#include "../../protocol/include/deregister_application_command.hpp" +#include "../../protocol/include/distribute_security_policies_command.hpp" +#include "../../protocol/include/dummy_command.hpp" +#include "../../protocol/include/expire_command.hpp" +#include "../../protocol/include/offer_service_command.hpp" +#include "../../protocol/include/offered_services_request_command.hpp" +#include "../../protocol/include/offered_services_response_command.hpp" +#include "../../protocol/include/ping_command.hpp" +#include "../../protocol/include/pong_command.hpp" +#include "../../protocol/include/register_application_command.hpp" +#include "../../protocol/include/register_events_command.hpp" +#include "../../protocol/include/registered_ack_command.hpp" +#include "../../protocol/include/release_service_command.hpp" +#include "../../protocol/include/remove_security_policy_command.hpp" +#include "../../protocol/include/remove_security_policy_response_command.hpp" +#include "../../protocol/include/request_service_command.hpp" +#include "../../protocol/include/resend_provided_events_command.hpp" +#include "../../protocol/include/routing_info_command.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../protocol/include/stop_offer_service_command.hpp" +#include "../../protocol/include/subscribe_ack_command.hpp" +#include "../../protocol/include/subscribe_command.hpp" +#include "../../protocol/include/subscribe_nack_command.hpp" +#include "../../protocol/include/unregister_event_command.hpp" +#include "../../protocol/include/unsubscribe_ack_command.hpp" +#include "../../protocol/include/unsubscribe_command.hpp" +#include "../../protocol/include/update_security_credentials_command.hpp" +#include "../../protocol/include/update_security_policy_command.hpp" +#include "../../protocol/include/update_security_policy_response_command.hpp" +#include "../../service_discovery/include/runtime.hpp" +#include "../../security/include/policy.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif + +#if defined(__QNX__) +#define HAVE_INET_PTON 1 +#include <boost/icl/concept/interval_associator.hpp> +#endif +namespace vsomeip_v3 { + +routing_manager_client::routing_manager_client(routing_manager_host *_host, + bool _client_side_logging, + const std::set<std::tuple<service_t, instance_t> > & _client_side_logging_filter) : + routing_manager_base(_host), + is_connected_(false), + is_started_(false), + state_(inner_state_type_e::ST_DEREGISTERED), + sender_(nullptr), + receiver_(nullptr), + register_application_timer_(io_), + request_debounce_timer_ (io_), + request_debounce_timer_running_(false), + client_side_logging_(_client_side_logging), + client_side_logging_filter_(_client_side_logging_filter) +#if defined(__linux__) || defined(ANDROID) + , is_local_link_available_(false) +#endif // defined(__linux__) || defined(ANDROID) +{ + + char its_hostname[1024]; + if (gethostname(its_hostname, sizeof(its_hostname)) == 0) { + set_client_host(its_hostname); + } +} + +routing_manager_client::~routing_manager_client() { +} + +void routing_manager_client::init() { + routing_manager_base::init(std::make_shared<endpoint_manager_base>(this, io_, configuration_)); + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (configuration_->is_local_routing()) { + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + } else { +#if defined(__linux__) || defined(ANDROID) + auto its_guest_address = configuration_->get_routing_guest_address(); + auto its_host_address = configuration_->get_routing_host_address(); + local_link_connector_ = std::make_shared<netlink_connector>( + io_, its_guest_address, boost::asio::ip::address(), + (its_guest_address != its_host_address)); + // if the guest is in the same node as the routing manager + // it should not require LINK to be UP to communicate + + if (local_link_connector_) { + local_link_connector_->register_net_if_changes_handler( + std::bind(&routing_manager_client::on_net_state_change, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } else { + VSOMEIP_WARNING << __func__ << ": (" << its_guest_address.to_string() << ":" + << its_host_address.to_string() << ")" + << " local_link_connector not initialized."; + } +#else + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); +#endif + } + } +} + +void routing_manager_client::start() { + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + is_started_ = true; + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (!sender_) { + // application has been stopped and started again + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + } + if (sender_) { + sender_->start(); + } + } +#if defined(__linux__) || defined(ANDROID) + } else { + if (local_link_connector_) + local_link_connector_->start(); +#endif // __linux__ || ANDROID + } +} + +void routing_manager_client::stop() { + std::unique_lock<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERING) { + register_application_timer_.cancel(); + } + + const std::chrono::milliseconds its_timeout(configuration_->get_shutdown_timeout()); + while (state_ == inner_state_type_e::ST_REGISTERING) { + std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); + if (status == std::cv_status::timeout) { + VSOMEIP_WARNING << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " registering timeout on stop"; + break; + } + } + + if (state_ == inner_state_type_e::ST_REGISTERED) { + deregister_application(); + // Waiting de-register acknowledge to synchronize shutdown + while (state_ == inner_state_type_e::ST_REGISTERED) { + std::cv_status status = state_condition_.wait_for(its_lock, its_timeout); + if (status == std::cv_status::timeout) { + VSOMEIP_WARNING << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " couldn't deregister application - timeout"; + break; + } + } + } + is_started_ = false; + its_lock.unlock(); + +#if defined(__linux__) || defined(ANDROID) + if (local_link_connector_) + local_link_connector_->stop(); +#endif + + { + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + request_debounce_timer_.cancel(); + } + + if (receiver_) { + receiver_->stop(); + } + receiver_ = nullptr; + + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->stop(); + } + // delete the sender + sender_ = nullptr; + } + + for (const auto client : ep_mgr_->get_connected_clients()) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client, true); + } + } + + if (configuration_->is_local_routing()) { + std::stringstream its_client; + its_client << utility::get_base_path(configuration_->get_network()) + << std::hex << get_client(); + #ifdef _WIN32 + ::_unlink(its_client.str().c_str()); + #else + + if (-1 == ::unlink(its_client.str().c_str())) { + VSOMEIP_ERROR<< "routing_manager_proxy::stop unlink failed (" + << its_client.str() << "): "<< std::strerror(errno); + } + #endif + } +} + +#if defined(__linux__) || defined(ANDROID) +void +routing_manager_client::on_net_state_change( + bool _is_interface, const std::string &_name, bool _is_available) { + + VSOMEIP_INFO << __func__ + << ": " << std::boolalpha << _is_interface << " " + << _name << " " + << std::boolalpha << _is_available; + + if (_is_interface) { + if (_is_available) { + if (!is_local_link_available_) { + + is_local_link_available_ = true; + + if (!receiver_) + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + + if (receiver_) { + receiver_->start(); + is_started_ = true; + + if (!sender_) + sender_ = ep_mgr_->create_local(VSOMEIP_ROUTING_CLIENT); + + if (sender_) { + host_->set_sec_client_port(sender_->get_local_port()); + sender_->start(); + } + } + } + } else { + if (is_local_link_available_) { + is_started_ = false; + + state_ = inner_state_type_e::ST_DEREGISTERED; + + if (sender_) { + on_disconnect(sender_); + host_->set_sec_client_port(VSOMEIP_SEC_PORT_UNSET); + sender_->stop(); + } + + if (receiver_) + receiver_->stop(); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_.clear(); + } + + is_local_link_available_ = false; + } + } + } +} +#endif // __linux__ || ANDROID + +std::shared_ptr<configuration> routing_manager_client::get_configuration() const { + return host_->get_configuration(); +} + +std::string routing_manager_client::get_env(client_t _client) const { + + std::lock_guard<std::mutex> its_known_clients_lock(known_clients_mutex_); + return get_env_unlocked(_client); +} + +std::string routing_manager_client::get_env_unlocked(client_t _client) const { + + auto find_client = known_clients_.find(_client); + if (find_client != known_clients_.end()) { + return find_client->second; + } + return ""; +} + +bool routing_manager_client::offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + if (!routing_manager_base::offer_service(_client, _service, _instance, _major, _minor)) { + VSOMEIP_WARNING << "routing_manager_client::offer_service," + << "routing_manager_base::offer_service returned false"; + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + send_offer_service(_client, _service, _instance, _major, _minor); + } + protocol::service offer(_service, _instance, _major, _minor ); + pending_offers_.insert(offer); + } + return true; +} + +void routing_manager_client::send_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + (void)_client; + + protocol::offer_service_command its_offer; + its_offer.set_client(get_client()); + its_offer.set_service(_service); + its_offer.set_instance(_instance); + its_offer.set_major(_major); + its_offer.set_minor(_minor); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_offer.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": offer_service serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + +} + +void routing_manager_client::stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + (void)_client; + + { + // Hold the mutex to ensure no placeholder event is created in between. + std::lock_guard<std::mutex> its_lock(stop_mutex_); + + routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor); + clear_remote_subscriber_count(_service, _instance); + + // Note: The last argument does not matter here as a proxy + // does not manage endpoints to the external network. + clear_service_info(_service, _instance, false); + } + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::stop_offer_service_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_major(_major); + its_command.set_minor(_minor); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": stop offer serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + } + auto it = pending_offers_.begin(); + while (it != pending_offers_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; + } + it++; + } + if (it != pending_offers_.end()) pending_offers_.erase(it); + } +} + +void routing_manager_client::request_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + routing_manager_base::request_service(_client, + _service, _instance, _major, _minor); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + size_t request_debouncing_time = configuration_->get_request_debouncing(host_->get_name()); + protocol::service request = { _service, _instance, _major, _minor }; + if (!request_debouncing_time) { + if (state_ == inner_state_type_e::ST_REGISTERED) { + std::set<protocol::service> requests; + requests.insert(request); + send_request_services(requests); + } + requests_.insert(request); + } else { + requests_to_debounce_.insert(request); + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + if (!request_debounce_timer_running_) { + request_debounce_timer_running_ = true; + request_debounce_timer_.expires_from_now(std::chrono::milliseconds(request_debouncing_time)); + request_debounce_timer_.async_wait( + std::bind( + &routing_manager_client::request_debounce_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + } + } + } +} + +void routing_manager_client::release_service(client_t _client, + service_t _service, instance_t _instance) { + routing_manager_base::release_service(_client, _service, _instance); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); + + bool pending(false); + auto it = requests_to_debounce_.begin(); + while (it != requests_to_debounce_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + pending = true; + } + it++; + } + if (it != requests_to_debounce_.end()) requests_to_debounce_.erase(it); + + if (!pending && state_ == inner_state_type_e::ST_REGISTERED) { + send_release_service(_client, _service, _instance); + } + + { + auto it = requests_.begin(); + while (it != requests_.end()) { + if (it->service_ == _service + && it->instance_ == _instance) { + break; + } + it++; + } + if (it != requests_.end()) requests_.erase(it); + } + } +} + + +void routing_manager_client::register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + + (void)_is_shadow; + (void)_is_cache_placeholder; + + bool is_cyclic(_cycle != std::chrono::milliseconds::zero()); + + const event_data_t registration = { + _service, + _instance, + _notifier, + _type, + _reliability, + _is_provided, + is_cyclic, + _eventgroups + }; + bool is_first(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + is_first = pending_event_registrations_.find(registration) + == pending_event_registrations_.end(); +#ifndef VSOMEIP_ENABLE_COMPAT + if (is_first) { + pending_event_registrations_.insert(registration); + } +#else + bool insert = true; + if (is_first) { + for (auto iter = pending_event_registrations_.begin(); + iter != pending_event_registrations_.end();) { + if (iter->service_ == _service + && iter->instance_ == _instance + && iter->notifier_ == _notifier + && iter->is_provided_ == _is_provided + && iter->type_ == event_type_e::ET_EVENT + && _type == event_type_e::ET_SELECTIVE_EVENT) { + iter = pending_event_registrations_.erase(iter); + iter = pending_event_registrations_.insert(registration).first; + is_first = true; + insert = false; + break; + } else { + iter++; + } + } + if (insert) { + pending_event_registrations_.insert(registration); + } + } +#endif + } + if (is_first || _is_provided) { + routing_manager_base::register_event(_client, + _service, _instance, + _notifier, + _eventgroups, _type, _reliability, + _cycle, _change_resets_cycle, _update_on_change, + _epsilon_change_func, + _is_provided); + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED && is_first) { + send_register_event(get_client(), _service, _instance, + _notifier, _eventgroups, _type, _reliability, + _is_provided, is_cyclic); + } + } +} + +void routing_manager_client::unregister_event(client_t _client, + service_t _service, instance_t _instance, event_t _notifier, + bool _is_provided) { + + routing_manager_base::unregister_event(_client, _service, _instance, + _notifier, _is_provided); + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::unregister_event_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_event(_notifier); + its_command.set_provided(_is_provided); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } + + for (auto iter = pending_event_registrations_.begin(); + iter != pending_event_registrations_.end(); ) { + if (iter->service_ == _service + && iter->instance_ == _instance + && iter->notifier_ == _notifier + && iter->is_provided_ == _is_provided) { + pending_event_registrations_.erase(iter); + break; + } else { + iter++; + } + } + } +} + +bool routing_manager_client::is_field(service_t _service, instance_t _instance, + event_t _event) const { + auto event = find_event(_service, _instance, _event); + if (event && event->is_field()) { + return true; + } + return false; +} + +void routing_manager_client::subscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) { + + (void)_client; + + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERED && is_available(_service, _instance, _major)) { + send_subscribe(get_client(), _service, _instance, _eventgroup, _major, _event, _filter ); + } + subscription_data_t subscription = { + _service, _instance, + _eventgroup, _major, + _event, _filter, + *_sec_client + }; + pending_subscriptions_.insert(subscription); +} + +void routing_manager_client::send_subscribe(client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) { + + if (_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(get_sec_client(), _client, _service, _instance, _eventgroup)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client + << " : routing_manager_proxy::subscribe: " + << " isn't allowed to subscribe to service/instance/event " + << _service << "/" << _instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), _service, _instance, _event)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << _client + << " : routing_manager_proxy::subscribe: " + << " isn't allowed to subscribe to service/instance/event " + << _service << "/" << _instance + << "/" << _event; + return; + } + } + + protocol::subscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(_major); + its_command.set_event(_event); + its_command.set_pending_id(PENDING_SUBSCRIPTION_ID); + its_command.set_filter(_filter); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + client_t its_target_client = find_local_client(_service, _instance); + if (its_target_client != VSOMEIP_ROUTING_CLIENT) { + std::shared_ptr<vsomeip_v3::endpoint> its_target = + ep_mgr_->find_or_create_local(its_target_client); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else { + VSOMEIP_ERROR << std::hex << std::setfill('0') << __func__ + << ": no target available to send subscription." + << " client=" << std::setw(4) << _client + << " service=" << std::setw(4) << _service << "." << std::setw(4) + << _instance << "." << std::setw(2) + << static_cast<std::uint16_t>(_major) << " event=" << std::setw(4) + << _event; + } + } else { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe command serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_subscribe_nack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id) { + + protocol::subscribe_nack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_subscriber); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (_subscriber != VSOMEIP_ROUTING_CLIENT + && _id == PENDING_SUBSCRIPTION_ID) { + auto its_target = ep_mgr_->find_local(_subscriber); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + return; + } + } + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe nack serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_subscribe_ack(client_t _subscriber, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id) { + + protocol::subscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_subscriber); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (_subscriber != VSOMEIP_ROUTING_CLIENT + && _id == PENDING_SUBSCRIPTION_ID) { + auto its_target = ep_mgr_->find_local(_subscriber); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + return; + } + } + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + VSOMEIP_ERROR << __func__ << ": subscribe ack serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::unsubscribe(client_t _client, + const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + + (void)_client; + (void)_sec_client; + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + remove_pending_subscription(_service, _instance, _eventgroup, _event); + + if (state_ == inner_state_type_e::ST_REGISTERED) { + + protocol::unsubscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(ANY_MAJOR); + its_command.set_event(_event); + its_command.set_pending_id(PENDING_SUBSCRIPTION_ID); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_target = ep_mgr_->find_local(_service, _instance); + if (its_target) { + its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else { + + VSOMEIP_ERROR << __func__ + << ": unsubscribe serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + } + } +} + +bool routing_manager_client::send(client_t _client, const byte_t *_data, + length_t _size, instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, bool _force) { + + (void)_client; + (void)_bound_client; + (void)_sec_client; + (void)_sent_from_remote; + bool is_sent(false); + bool has_remote_subscribers(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ != inner_state_type_e::ST_REGISTERED) { + return false; + } + } + if (client_side_logging_) { + if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + if (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_service, _instance)))) { + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + VSOMEIP_INFO << "routing_manager_client::send: (" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_method << ":" + << std::setw(4) << its_session << ":" + << std::setw(4) << its_client << "] " + << "type=" << std::hex << static_cast<std::uint32_t>(_data[VSOMEIP_MESSAGE_TYPE_POS]) + << " thread=" << std::hex << std::this_thread::get_id(); + } + } else { + VSOMEIP_ERROR << "routing_manager_client::send: (" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << "): message too short to log: " << std::dec << _size; + } + } + if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + std::shared_ptr<endpoint> its_target; + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Request + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + client_t its_client = find_local_client(its_service, _instance); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (is_client_known(its_client)) { + its_target = ep_mgr_->find_or_create_local(its_client); + } + } + } else if (!utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + // Response + client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + if (its_client != VSOMEIP_ROUTING_CLIENT) { + if (is_client_known(its_client)) { + its_target = ep_mgr_->find_or_create_local(its_client); + } + } + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client == VSOMEIP_ROUTING_CLIENT) { + // notify + has_remote_subscribers = send_local_notification(get_client(), _data, _size, + _instance, _reliable, _status_check, _force); + } else if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]) && + _client != VSOMEIP_ROUTING_CLIENT) { + // notify_one + its_target = ep_mgr_->find_local(_client); + if (its_target) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#endif + return send_local(its_target, get_client(), _data, _size, + _instance, _reliable, protocol::id_e::SEND_ID, _status_check); + } + } + // If no direct endpoint could be found + // or for notifications ~> route to routing_manager_stub +#ifdef USE_DLT + bool message_to_stub(false); +#endif + if (!its_target) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + its_target = sender_; +#ifdef USE_DLT + message_to_stub = true; +#endif + } else { + return false; + } + } + + bool send(true); + protocol::id_e its_command(protocol::id_e::SEND_ID); + + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + if (_client != VSOMEIP_ROUTING_CLIENT) { + its_command = protocol::id_e::NOTIFY_ONE_ID; + } else { + its_command = protocol::id_e::NOTIFY_ID; + // Do we need to deliver a notification to the routing manager? + // Only for services which already have remote clients subscribed to + send = has_remote_subscribers; + } + } +#ifdef USE_DLT + else if (!message_to_stub) { + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif + if (send) { + is_sent = send_local(its_target, + (its_command == protocol::id_e::NOTIFY_ONE_ID ? _client : get_client()), + _data, _size, _instance, _reliable, its_command, _status_check); + } + } + return is_sent; +} + +bool routing_manager_client::send_to(const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message) { + + (void)_client; + (void)_target; + (void)_message; + + return false; +} + +bool routing_manager_client::send_to( + const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, instance_t _instance) { + + (void)_target; + (void)_data; + (void)_size; + (void)_instance; + + return false; +} + +void routing_manager_client::on_connect(const std::shared_ptr<endpoint>& _endpoint) { + + _endpoint->set_connected(true); + _endpoint->set_established(true); + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (_endpoint != sender_) { + return; + } + } + is_connected_ = true; + assign_client(); +} + +void routing_manager_client::on_disconnect(const std::shared_ptr<endpoint>& _endpoint) { + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + is_connected_ = !(_endpoint == sender_); + } + if (!is_connected_) { + VSOMEIP_INFO << "routing_manager_client::on_disconnect: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " calling host_->on_state with DEREGISTERED"; + host_->on_state(state_type_e::ST_DEREGISTERED); + } +} + +void routing_manager_client::on_message( + const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + + (void)_receiver; + (void)_is_multicast; + (void)_remote_address; + (void)_remote_port; + +#if 0 + std::stringstream msg; + msg << "rmp::on_message<" << std::hex << get_client() << ">: "; + for (length_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + protocol::id_e its_id; + client_t its_client; + service_t its_service; + instance_t its_instance; + eventgroup_t its_eventgroup; + event_t its_event; + major_version_t its_major; + client_t routing_host_id = configuration_->get_id( + configuration_->get_routing_host_name()); + client_t its_subscriber; + remote_subscription_id_t its_pending_id(PENDING_SUBSCRIPTION_ID); + std::uint32_t its_remote_subscriber_count(0); +#ifndef VSOMEIP_DISABLE_SECURITY + bool is_internal_policy_update(false); +#endif // !VSOMEIP_DISABLE_SECURITY + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + auto its_policy_manager = configuration_->get_policy_manager(); + if (!its_policy_manager) + return; + + protocol::dummy_command its_dummy_command; + its_dummy_command.deserialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + its_id = its_dummy_command.get_id(); + its_client = its_dummy_command.get_client(); + + bool is_from_routing(false); + if (configuration_->is_security_enabled()) { + if (configuration_->is_local_routing()) { + // if security is enabled, client ID of routing must be configured + // and credential passing is active. Otherwise bound client is zero by default + is_from_routing = (_bound_client == routing_host_id); + } else { + is_from_routing = (_remote_address == configuration_->get_routing_host_address() + && _remote_port == configuration_->get_routing_host_port() + 1); + } + } else { + is_from_routing = (its_client == routing_host_id); + } + + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && !is_from_routing && _bound_client != its_client) { + VSOMEIP_WARNING << "Client " << std::hex << std::setw(4) << std::setfill('0') + << get_client() << " received a message with command " << int(its_id) + << " from " << std::hex << std::setw(4) << std::setfill('0') + << its_client << " which doesn't match the bound client " << std::hex + << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } + + switch (its_id) { + case protocol::id_e::SEND_ID: + { + protocol::send_command its_send_command(protocol::id_e::SEND_ID); + its_send_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto a_deserializer = get_deserializer(); + a_deserializer->set_data(its_send_command.get_message()); + std::shared_ptr<message_impl> its_message(a_deserializer->deserialize_message()); + a_deserializer->reset(); + put_deserializer(a_deserializer); + + if (its_message) { + its_message->set_instance(its_send_command.get_instance()); + its_message->set_reliable(its_send_command.is_reliable()); + its_message->set_check_result(its_send_command.get_status()); + if (_sec_client) + its_message->set_sec_client(*_sec_client); + its_message->set_env(get_env(_bound_client)); + + if (!is_from_routing) { + if (utility::is_notification(its_message->get_message_type())) { + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " received a notification from client 0x" << _bound_client + << " which does not offer service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return; + } + cache_event_payload(its_message); + } + } else if (utility::is_request(its_message->get_message_type())) { + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && its_message->get_client() != _bound_client) { + VSOMEIP_WARNING << std::hex << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " received a request from client 0x" + << std::hex << std::setw(4) << std::setfill('0') << its_message->get_client() + << " to service/instance/method " << its_message->get_service() + << "/" << its_message->get_instance() << "/" << its_message->get_method() + << " which doesn't match the bound client 0x" + << std::hex << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << its_message->get_client() + << " : routing_manager_client::on_message: " + << "isn't allowed to send a request to service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } + } else { // response + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " received a response from client 0x" << _bound_client + << " which does not offer service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return; + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a response from service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return; + } + } + } + } else { + if (!configuration_->is_remote_access_allowed()) { + // if the message is from routing manager, check if + // policy allows remote requests. + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << std::hex << "Security: Remote clients via routing manager with client ID 0x" << its_client + << " are not allowed to communicate with service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively with client 0x" << get_client() + << " ~> Skip message!"; + return; + } else if (utility::is_notification(its_message->get_message_type())) { + // As subscription is sent on eventgroup level, incoming remote event ID's + // need to be checked as well if remote clients are allowed + // and the local policy only allows specific events in the eventgroup to be received. + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_client::on_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from remote clients via routing manager with client ID 0x" + << routing_host_id + << " ~> Skip message!"; + return; + } + cache_event_payload(its_message); + } + } + #ifdef USE_DLT + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_message->get_service(), its_message->get_instance()))))) { + trace::header its_header; + if (its_header.prepare(nullptr, false, its_send_command.get_instance())) { + uint32_t its_message_size = its_send_command.get_size(); + if (its_message_size >= uint32_t{vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE}) + its_message_size -= uint32_t{vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE}; + else + its_message_size = 0; + + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + &_data[vsomeip_v3::protocol::SEND_COMMAND_HEADER_SIZE], its_message_size); + } + } + #endif + + host_->on_message(std::move(its_message)); + } else + VSOMEIP_ERROR << "Routing proxy: on_message: " + << "SomeIP-Header deserialization failed!"; + } else + VSOMEIP_ERROR << __func__ + << ": send command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::ASSIGN_CLIENT_ACK_ID: + { + client_t its_assigned_client(VSOMEIP_CLIENT_UNSET); + protocol::assign_client_ack_command its_ack_command; + its_ack_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + its_assigned_client = its_ack_command.get_assigned(); + + on_client_assign_ack(its_assigned_client); + break; + } + + case protocol::id_e::ROUTING_INFO_ID: + if (!configuration_->is_security_enabled() || is_from_routing) { + on_routing_info(_data, _size); + } else { + VSOMEIP_WARNING << "routing_manager_client::on_message: " + << "Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0')<< get_client() + << " received an routing info from a client which isn't the routing manager" + << " : Skip message!"; + } + break; + + case protocol::id_e::PING_ID: + { + protocol::ping_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + send_pong(); + VSOMEIP_TRACE << "PING(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": ping command deserialization failed (" + << std::dec << int(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ID: + { + protocol::subscribe_command its_subscribe_command; + its_subscribe_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_command.get_service(); + its_instance = its_subscribe_command.get_instance(); + its_eventgroup = its_subscribe_command.get_eventgroup(); + its_major = its_subscribe_command.get_major(); + its_event = its_subscribe_command.get_event(); + its_pending_id = its_subscribe_command.get_pending_id(); + auto its_filter = its_subscribe_command.get_filter(); + + std::unique_lock<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); + if (its_pending_id != PENDING_SUBSCRIPTION_ID) { + its_lock.unlock(); +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); +#endif + auto its_info = find_service(its_service, its_instance); + if (its_info) { + // Remote subscriber: Notify routing manager initially + count subscribes + auto self = shared_from_this(); + host_->on_subscription( + its_service, its_instance, its_eventgroup, its_client, _sec_client, + get_env(its_client), true, + [this, self, its_client, its_service, its_instance, its_eventgroup, + its_event, its_filter, its_pending_id, + its_major](const bool _subscription_accepted) { + std::uint32_t its_count(0); + if (_subscription_accepted) { + send_subscribe_ack(its_client, its_service, its_instance, + its_eventgroup, its_event, + its_pending_id); + std::set<event_t> its_already_subscribed_events; + bool inserted = insert_subscription( + its_service, its_instance, its_eventgroup, + its_event, its_filter, VSOMEIP_ROUTING_CLIENT, + &its_already_subscribed_events); + if (inserted) { + notify_remote_initially(its_service, its_instance, + its_eventgroup, + its_already_subscribed_events); + } +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(its_service, its_instance, + its_eventgroup, its_client, true); +#endif + its_count = get_remote_subscriber_count( + its_service, its_instance, its_eventgroup, true); + } else { + send_subscribe_nack(its_client, its_service, its_instance, + its_eventgroup, its_event, + its_pending_id); + } + VSOMEIP_INFO + << "SUBSCRIBE(" << std::hex << std::setw(4) + << std::setfill('0') << its_client << "): [" << std::hex + << std::setw(4) << std::setfill('0') << its_service + << "." << std::hex << std::setw(4) << std::setfill('0') + << its_instance << "." << std::hex << std::setw(4) + << std::setfill('0') << its_eventgroup << ":" + << std::hex << std::setw(4) << std::setfill('0') + << its_event << ":" << std::dec << (uint16_t)its_major + << "] " << std::boolalpha + << (its_pending_id != PENDING_SUBSCRIPTION_ID) << " " + << (_subscription_accepted + ? std::to_string(its_count) + " accepted." + : "not accepted."); + }); + } else { + send_subscribe_nack(its_client, its_service, its_instance, its_eventgroup, + its_event, its_pending_id); + } +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state( + its_client, its_service, its_instance, its_eventgroup, its_event); +#endif + } else if (is_client_known(its_client)) { + its_lock.unlock(); + if (!is_from_routing) { + if (its_event == ANY_EVENT) { + if (!is_subscribe_to_any_event_allowed(_sec_client, its_client, its_service, its_instance, its_eventgroup)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << " isn't allowed to subscribe to service/instance/event " + << its_service << "/" << its_instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_event)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/" << its_event + << " which violates the security policy ~> Skip subscribe!"; + return; + } + } + } else { + if (!configuration_->is_remote_access_allowed()) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_client::on_message: " + << std::hex << "Routing manager with client ID 0x" + << its_client + << " isn't allowed to subscribe to service/instance/event " + << its_service << "/" << its_instance + << "/" << its_event + << " respectively to client 0x" << get_client() + << " ~> Skip Subscribe!"; + return; + } + } + + // Local & already known subscriber: create endpoint + send (N)ACK + insert subscription +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(its_client, its_service, + its_instance, its_eventgroup, its_event, subscription_state_e::IS_SUBSCRIBING); +#endif + (void) ep_mgr_->find_or_create_local(its_client); + auto self = shared_from_this(); + auto its_env = get_env(its_client); + + auto its_info = find_service(its_service, its_instance); + if (its_info) { + host_->on_subscription( + its_service, its_instance, its_eventgroup, its_client, _sec_client, + its_env, true, + [this, self, its_client, its_filter, _sec_client, its_env, + its_service, its_instance, its_eventgroup, its_event, + its_major](const bool _subscription_accepted) { + if (!_subscription_accepted) { + send_subscribe_nack(its_client, its_service, its_instance, + its_eventgroup, its_event, + PENDING_SUBSCRIPTION_ID); + } else { + send_subscribe_ack(its_client, its_service, its_instance, + its_eventgroup, its_event, + PENDING_SUBSCRIPTION_ID); + routing_manager_base::subscribe( + its_client, _sec_client, its_service, its_instance, + its_eventgroup, its_major, its_event, its_filter); +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(its_service, its_instance, + its_eventgroup, its_client); +#endif + } + }); + } else { + send_subscribe_nack(its_client, its_service, its_instance, its_eventgroup, + its_event, PENDING_SUBSCRIPTION_ID); + } +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state( + its_client, its_service, its_instance, its_eventgroup, its_event); +#endif + } else { + if (_sec_client) { + // Local & not yet known subscriber ~> set pending until subscriber gets known! + subscription_data_t subscription = { + its_service, its_instance, + its_eventgroup, its_major, + its_event, its_filter, + *_sec_client + }; + pending_incoming_subscriptions_[its_client].insert(subscription); + } else { + VSOMEIP_WARNING << __func__ + << ": Local subscription without security info."; + } + } + + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { // local subscription + VSOMEIP_INFO << "SUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << ":" + << std::setw(4) << its_event << ":" + << std::dec << (uint16_t)its_major << "]"; + } + } else { + VSOMEIP_ERROR << __func__ + << ": subscribe command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } + break; + } + + case protocol::id_e::UNSUBSCRIBE_ID: + { + protocol::unsubscribe_command its_unsubscribe; + its_unsubscribe.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_unsubscribe.get_client(); + its_service = its_unsubscribe.get_service(); + its_instance = its_unsubscribe.get_instance(); + its_eventgroup = its_unsubscribe.get_eventgroup(); + its_event = its_unsubscribe.get_event(); + its_pending_id = its_unsubscribe.get_pending_id(); + + host_->on_subscription(its_service, its_instance, its_eventgroup, + its_client, _sec_client, get_env(its_client), false, + [](const bool _subscription_accepted){ + (void)_subscription_accepted; + } + ); + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { + // Local subscriber: withdraw subscription + routing_manager_base::unsubscribe(its_client, _sec_client, its_service, its_instance, its_eventgroup, its_event); + } else { + // Remote subscriber: withdraw subscription only if no more remote subscriber exists + its_remote_subscriber_count = get_remote_subscriber_count(its_service, + its_instance, its_eventgroup, false); + if (!its_remote_subscriber_count) { + routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, nullptr, its_service, + its_instance, its_eventgroup, its_event); + } + send_unsubscribe_ack(its_service, its_instance, its_eventgroup, its_pending_id); + } + VSOMEIP_INFO << "UNSUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_event << "] " + << (bool)(its_pending_id != PENDING_SUBSCRIPTION_ID) << " " + << std::dec << its_remote_subscriber_count; + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::EXPIRE_ID: + { + protocol::expire_command its_expire; + its_expire.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_expire.get_client(); + its_service = its_expire.get_service(); + its_instance = its_expire.get_instance(); + its_eventgroup = its_expire.get_eventgroup(); + its_event = its_expire.get_event(); + its_pending_id = its_expire.get_pending_id(); + + host_->on_subscription(its_service, its_instance, its_eventgroup, its_client, + _sec_client, get_env(its_client), false, + [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + if (its_pending_id == PENDING_SUBSCRIPTION_ID) { + // Local subscriber: withdraw subscription + routing_manager_base::unsubscribe(its_client, _sec_client, + its_service, its_instance, its_eventgroup, its_event); + } else { + // Remote subscriber: withdraw subscription only if no more remote subscriber exists + its_remote_subscriber_count = get_remote_subscriber_count(its_service, + its_instance, its_eventgroup, false); + if (!its_remote_subscriber_count) { + routing_manager_base::unsubscribe(VSOMEIP_ROUTING_CLIENT, nullptr, + its_service, its_instance, its_eventgroup, its_event); + } + } + VSOMEIP_INFO << "EXPIRED SUBSCRIPTION(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_event << "] " + << (bool)(its_pending_id != PENDING_SUBSCRIPTION_ID) << " " + << std::dec << its_remote_subscriber_count; + } else + VSOMEIP_ERROR << __func__ + << ": expire deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_NACK_ID: + { + protocol::subscribe_nack_command its_subscribe_nack; + its_subscribe_nack.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_nack.get_service(); + its_instance = its_subscribe_nack.get_instance(); + its_eventgroup = its_subscribe_nack.get_eventgroup(); + its_subscriber = its_subscribe_nack.get_subscriber(); + its_event = its_subscribe_nack.get_event(); + + on_subscribe_nack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); + VSOMEIP_INFO << "SUBSCRIBE NACK(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_event << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": subscribe nack command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ACK_ID: + { + protocol::subscribe_ack_command its_subscribe_ack; + its_subscribe_ack.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_service = its_subscribe_ack.get_service(); + its_instance = its_subscribe_ack.get_instance(); + its_eventgroup = its_subscribe_ack.get_eventgroup(); + its_subscriber = its_subscribe_ack.get_subscriber(); + its_event = its_subscribe_ack.get_event(); + + on_subscribe_ack(its_subscriber, its_service, its_instance, its_eventgroup, its_event); + VSOMEIP_INFO << "SUBSCRIBE ACK(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_event << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::OFFERED_SERVICES_RESPONSE_ID: + { + protocol::offered_services_response_command its_response; + its_response.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + if (!configuration_->is_security_enabled() || is_from_routing) { + on_offered_services_info(its_response); + } else { + VSOMEIP_WARNING << std::hex << "Security: Client 0x" << get_client() + << " received an offered services info from a client which isn't the routing manager" + << " : Skip message!"; + } + } else + VSOMEIP_ERROR << __func__ + << ": offered services response command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + case protocol::id_e::RESEND_PROVIDED_EVENTS_ID: + { + protocol::resend_provided_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + resend_provided_event_registrations(); + send_resend_provided_event_response(its_command.get_remote_offer_id()); + + VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" + << std::hex << std::setw(4) << std::setfill('0') + << its_command.get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": resend provided events command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + case protocol::id_e::SUSPEND_ID: + { + on_suspend(); // cleanup remote subscribers + break; + } +#ifndef VSOMEIP_DISABLE_SECURITY + case protocol::id_e::UPDATE_SECURITY_POLICY_INT_ID: + is_internal_policy_update = true; + [[gnu::fallthrough]]; + case protocol::id_e::UPDATE_SECURITY_POLICY_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::update_security_policy_command its_command(is_internal_policy_update); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + auto its_policy = its_command.get_policy(); + uid_t its_uid; + gid_t its_gid; + if (its_policy->get_uid_gid(its_uid, its_gid)) { + if (is_internal_policy_update + || its_policy_manager->is_policy_update_allowed(its_uid, its_policy)) { + its_policy_manager->update_security_policy(its_uid, its_gid, its_policy); + send_update_security_policy_response(its_command.get_update_id()); + } + } else { + VSOMEIP_ERROR << "vSomeIP Security: Policy has no valid uid/gid!"; + } + } else { + VSOMEIP_ERROR << "vSomeIP Security: Policy deserialization failed!"; + } + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " received a security policy update from a client which isn't the routing manager" + << " : Skip message!"; + } + break; + } + + case protocol::id_e::REMOVE_SECURITY_POLICY_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::remove_security_policy_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + uid_t its_uid(its_command.get_uid()); + gid_t its_gid(its_command.get_gid()); + + if (its_policy_manager->is_policy_removal_allowed(its_uid)) { + its_policy_manager->remove_security_policy(its_uid, its_gid); + send_remove_security_policy_response(its_command.get_update_id()); + } + } else + VSOMEIP_ERROR << __func__ + << ": remove security policy command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << "received a security policy removal from a client which isn't the routing manager" + << " : Skip message!"; + break; + } + + case protocol::id_e::DISTRIBUTE_SECURITY_POLICIES_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::distribute_security_policies_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + for (auto p : its_command.get_policies()) { + uid_t its_uid; + gid_t its_gid; + p->get_uid_gid(its_uid, its_gid); + if (its_policy_manager->is_policy_update_allowed(its_uid, p)) + its_policy_manager->update_security_policy(its_uid, its_gid, p); + } + } else + VSOMEIP_ERROR << __func__ + << ": distribute security policies command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << " received a security policy distribution command from a client which isn't the routing manager" + << " : Skip message!"; + break; + } + + case protocol::id_e::UPDATE_SECURITY_CREDENTIALS_ID: + { + if (!configuration_->is_security_enabled() || is_from_routing) { + protocol::update_security_credentials_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_update_security_credentials(its_command); + } else + VSOMEIP_ERROR << __func__ + << ": update security credentials command deserialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_message: " + << "received a security credential update from a client which isn't the routing manager" + << " : Skip message!"; + + break; + } +#endif // !VSOMEIP_DISABLE_SECURITY + case protocol::id_e::CONFIG_ID: { + protocol::config_command its_command; + protocol::error_e its_command_error; + its_command.deserialize(its_buffer, its_command_error); + if (its_command_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ << ": config command deserialization failed (" << std::dec + << static_cast<int>(its_command_error) << ")"; + break; + } + if (its_command.contains("hostname")) { + add_known_client(its_command.get_client(), its_command.at("hostname")); + } + break; + } + default: + break; + } + } else + VSOMEIP_ERROR << __func__ + << ": dummy command deserialization failed (" + << std::dec << static_cast<int>(its_error) + << ")"; +} + +void routing_manager_client::on_routing_info( + const byte_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "rmp::on_routing_info(" << std::hex << std::setw(4) << std::setfill('0') << get_client() << "): "; + for (uint32_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + auto its_policy_manager = configuration_->get_policy_manager(); + if (!its_policy_manager) + return; + + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + protocol::routing_info_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ + << ": deserializing routing info command failed (" + << static_cast<int>(its_error) + << ")"; + return; + } + + for (const auto &e : its_command.get_entries()) { + auto its_client = e.get_client(); + switch (e.get_type()) { + case protocol::routing_info_entry_type_e::RIE_ADD_CLIENT: + { + auto its_address = e.get_address(); + if (!its_address.is_unspecified()) { + add_guest(its_client, its_address, e.get_port()); + add_known_client(its_client, ""); + } + + if (its_client == get_client()) { + VSOMEIP_INFO << "Application/Client " + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " (" << host_->get_name() << ") is registered."; +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (!its_policy_manager->check_credentials(get_client(), get_sec_client())) { + VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::on_routing_info: RIE_ADD_CLIENT: isn't allowed" + << " to use the server endpoint due to credential check failed!"; + deregister_application(); + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + return; + } +#endif + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_REGISTERING) { + boost::system::error_code ec; + register_application_timer_.cancel(ec); + send_registered_ack(); + send_pending_commands(); + state_ = inner_state_type_e::ST_REGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + } + } + + // inform host about its own registration state changes + if (state_ == inner_state_type_e::ST_REGISTERED) { + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_REGISTERED)); + } + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT: + { + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + known_clients_.erase(its_client); + } + if (its_client == get_client()) { + its_policy_manager->remove_client_to_sec_client_mapping(its_client); + VSOMEIP_INFO << "Application/Client " << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " (" << host_->get_name() << ") is deregistered."; + + // inform host about its own registration state changes + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + state_ = inner_state_type_e::ST_DEREGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + } + } else if (its_client != VSOMEIP_ROUTING_CLIENT) { + remove_local(its_client, true); + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE: + { + auto its_address = e.get_address(); + if (!its_address.is_unspecified()) { + add_guest(its_client, its_address, e.get_port()); + add_known_client(its_client, ""); + } + { + // Add yet unknown clients that offer services. Otherwise, + // the service cannot be used. The entry will be overwritten, + // when the offering clients connects. + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + if (known_clients_.find(its_client) == known_clients_.end()) { + known_clients_[its_client] = ""; + } + } + + for (const auto &s : e.get_services()) { + + const auto its_service(s.service_); + const auto its_instance(s.instance_); + const auto its_major(s.major_); + const auto its_minor(s.minor_); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + + // Check whether the service instance is already known. If yes, + // continue with the next service within the routing info. + auto found_service = local_services_.find(its_service); + if (found_service != local_services_.end()) { + if (found_service->second.find(its_instance) != found_service->second.end()) + continue; + } + + local_services_[its_service][its_instance] + = std::make_tuple(its_major, its_minor, its_client); + } + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + send_pending_subscriptions(its_service, its_instance, its_major); + } + host_->on_availability(its_service, its_instance, + availability_state_e::AS_AVAILABLE, its_major, its_minor); + VSOMEIP_INFO << "ON_AVAILABLE(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance + << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; + } + break; + } + + case protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE: + { + for (const auto &s : e.get_services()) { + const auto its_service(s.service_); + const auto its_instance(s.instance_); + const auto its_major(s.major_); + const auto its_minor(s.minor_); + + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_.find(its_service); + if (found_service != local_services_.end()) { + found_service->second.erase(its_instance); + // move previously offering client to history + local_services_history_[its_service][its_instance].insert(its_client); + if (found_service->second.size() == 0) { + local_services_.erase(its_service); + } + } + } + on_stop_offer_service(its_service, its_instance, its_major, its_minor); + host_->on_availability(its_service, its_instance, + availability_state_e::AS_UNAVAILABLE, its_major, its_minor); + VSOMEIP_INFO << "ON_UNAVAILABLE(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance + << ":" << std::dec << int(its_major) << "." << std::dec << its_minor << "]"; + } + break; + } + + default: + VSOMEIP_ERROR << __func__ + << ": Unknown routing info entry type (" + << static_cast<int>(e.get_type()) + << ")"; + break; + } + } + + { + struct subscription_info { + service_t service_id_; + instance_t instance_id_; + eventgroup_t eventgroup_id_; + client_t client_id_; + major_version_t major_; + event_t event_; + std::shared_ptr<debounce_filter_impl_t> filter_; + vsomeip_sec_client_t sec_client_; + std::string env_; + }; + std::lock_guard<std::recursive_mutex> its_lock(incoming_subscriptions_mutex_); + std::forward_list<struct subscription_info> subscription_actions; + if (pending_incoming_subscriptions_.size()) { + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + for (const auto &k : known_clients_) { + auto its_client = pending_incoming_subscriptions_.find(k.first); + if (its_client != pending_incoming_subscriptions_.end()) { + for (const auto &subscription : its_client->second) { + subscription_actions.push_front( + { subscription.service_, subscription.instance_, + subscription.eventgroup_, k.first, + subscription.major_, subscription.event_, + subscription.filter_, + subscription.sec_client_, + get_env_unlocked(k.first)}); + } + } + } + } + for (const subscription_info &si : subscription_actions) { +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(si.client_id_, si.service_id_, si.instance_id_, + si.eventgroup_id_, si.event_, subscription_state_e::IS_SUBSCRIBING); +#endif + (void) ep_mgr_->find_or_create_local(si.client_id_); + auto self = shared_from_this(); + host_->on_subscription( + si.service_id_, si.instance_id_, si.eventgroup_id_, + si.client_id_, &si.sec_client_, si.env_, true, + [this, self, si](const bool _subscription_accepted) { + if (!_subscription_accepted) { + send_subscribe_nack(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); + } else { + send_subscribe_ack(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_, PENDING_SUBSCRIPTION_ID); + routing_manager_base::subscribe(si.client_id_, &si.sec_client_, + si.service_id_, si.instance_id_, si.eventgroup_id_, + si.major_, si.event_, si.filter_); +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(si.service_id_, + si.instance_id_, si.eventgroup_id_, si.client_id_); +#endif + } +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::erase_incoming_subscription_state(si.client_id_, si.service_id_, + si.instance_id_, si.eventgroup_id_, si.event_); +#endif + { + std::lock_guard<std::recursive_mutex> its_lock2(incoming_subscriptions_mutex_); + pending_incoming_subscriptions_.erase(si.client_id_); + } + }); + } + } + } +} + +void routing_manager_client::on_offered_services_info( + protocol::offered_services_response_command &_command) { + + std::vector<std::pair<service_t, instance_t>> its_offered_services_info; + + for (const auto &s : _command.get_services()) + its_offered_services_info.push_back(std::make_pair(s.service_, s.instance_)); + + host_->on_offered_services_info(its_offered_services_info); +} + +void routing_manager_client::reconnect(const std::map<client_t, std::string> &_clients) { + auto its_policy_manager = configuration_->get_policy_manager(); + if (!its_policy_manager) + return; + + // inform host about its own registration state changes + host_->on_state(static_cast<state_type_e>(inner_state_type_e::ST_DEREGISTERED)); + + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + state_ = inner_state_type_e::ST_DEREGISTERED; + // Notify stop() call about clean deregistration + state_condition_.notify_one(); + } + + + // Remove all local connections/endpoints + for (const auto &c : _clients) { + if (c.first != VSOMEIP_ROUTING_CLIENT) { + remove_local(c.first, true); + } + } + + VSOMEIP_INFO << std::hex << "Application/Client " + << std::hex << std::setw(4) << std::setfill('0') << get_client() + <<": Reconnecting to routing manager."; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (!its_policy_manager->check_credentials(get_client(), get_sec_client())) { + VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " : routing_manager_client::reconnect: isn't allowed" + << " to use the server endpoint due to credential check failed!"; + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->stop(); + } + return; + } +#endif + + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->restart(); + } +} + +void routing_manager_client::assign_client() { + + VSOMEIP_INFO << __func__ << ": (" << std::hex << std::setw(4) << std::setfill('0') + << get_client() << ":" << host_->get_name() << ")"; + + protocol::assign_client_command its_command; + its_command.set_client(get_client()); + its_command.set_name(host_->get_name()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << __func__ << ": command creation failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return; + } + + std::lock_guard<std::mutex> its_state_lock(state_mutex_); + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + if (state_ != inner_state_type_e::ST_DEREGISTERED) { + VSOMEIP_WARNING << __func__ << ": (" << std::hex << std::setw(4) << std::setfill('0') + << get_client() << ") Non-Deregistered State Set. Returning"; + return; + } + state_ = inner_state_type_e::ST_ASSIGNING; + + sender_->send(&its_buffer[0], static_cast<uint32_t>(its_buffer.size())); + + boost::system::error_code ec; + register_application_timer_.cancel(ec); + register_application_timer_.expires_from_now(std::chrono::milliseconds(3000)); + register_application_timer_.async_wait( + std::bind( + &routing_manager_client::assign_client_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + } else { + VSOMEIP_WARNING << __func__ << ": (" << std::hex << std::setw(4) << std::setfill('0') + << get_client() << ") sender not initialized. Ignoring client assignment"; + } + } + else { + VSOMEIP_WARNING << __func__ << ": (" << std::hex << std::setw(4) << std::setfill('0') + << get_client() << ") not connected. Ignoring client assignment"; + } +} + +void routing_manager_client::register_application() { + + if (!receiver_) { + VSOMEIP_ERROR << __func__ + << "Cannot register. Local server endpoint does not exist."; + return; + } + + auto its_configuration(get_configuration()); + if (its_configuration->is_local_routing()) { + VSOMEIP_INFO << "Registering to routing manager @ " + << its_configuration->get_network() << "-0"; + } else { + auto its_routing_address(its_configuration->get_routing_host_address()); + auto its_routing_port(its_configuration->get_routing_host_port()); + VSOMEIP_INFO << "Registering to routing manager @ " + << its_routing_address.to_string() << ":" << its_routing_port; + } + + protocol::register_application_command its_command; + its_command.set_client(get_client()); + its_command.set_port(receiver_->get_local_port()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + state_ = inner_state_type_e::ST_REGISTERING; + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + + register_application_timer_.cancel(); + register_application_timer_.expires_from_now(std::chrono::milliseconds(3000)); + register_application_timer_.async_wait( + std::bind( + &routing_manager_client::register_application_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + + // Send a `config_command` to share our hostname with the other application. + protocol::config_command its_command_config; + its_command_config.set_client(get_client()); + its_command_config.insert("hostname", get_client_host()); + + std::vector<byte_t> its_buffer_config; + its_command_config.serialize(its_buffer_config, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + sender_->send(&its_buffer_config[0], + static_cast<uint32_t>(its_buffer_config.size())); + } else { + VSOMEIP_ERROR << __func__ << ": config command serialization failed(" + << std::dec << int(its_error) << ")"; + } + } + } + } else { + VSOMEIP_ERROR << __func__ << ": register application command serialization failed(" + << std::dec << int(its_error) << ")"; + } +} + +void routing_manager_client::deregister_application() { + + protocol::deregister_application_command its_command; + its_command.set_client(get_client()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else + VSOMEIP_ERROR << __func__ + << ": deregister application command serialization failed(" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_pong() const { + + protocol::pong_command its_command; + its_command.set_client(get_client()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if (is_connected_) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } + } else + VSOMEIP_ERROR << __func__ + << ": pong command serialization failed(" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_request_services(const std::set<protocol::service> &_requests) { + + if (!_requests.size()) { + return; + } + + protocol::request_service_command its_command; + its_command.set_client(get_client()); + its_command.set_services(_requests); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else { + VSOMEIP_ERROR << __func__ << ": request service serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + } +} + +void routing_manager_client::send_release_service(client_t _client, service_t _service, + instance_t _instance) { + + (void)_client; + + protocol::release_service_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } +} + +void routing_manager_client::send_pending_event_registrations(client_t _client) { + + protocol::register_events_command its_command; + its_command.set_client(_client); + std::set<vsomeip_v3::routing_manager_client::event_data_t>::iterator it = pending_event_registrations_.begin(); + + while(it != pending_event_registrations_.end()) + { + for(; it!=pending_event_registrations_.end(); it++) { + protocol::register_event reg(it->service_, it->instance_, it->notifier_, it->type_, + it->is_provided_, it->reliability_, it->is_cyclic_ + , (uint16_t)it->eventgroups_.size(), it->eventgroups_); + if(!its_command.add_registration(reg)) {break;} + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": register event command serialization failed (" + << std::dec << int(its_error) << ")"; + } +} + +void routing_manager_client::send_register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, + reliability_type_e _reliability, + bool _is_provided, bool _is_cyclic) { + + (void)_client; + + protocol::register_events_command its_command; + its_command.set_client(get_client()); + + protocol::register_event reg(_service, _instance, _notifier, _type, + _is_provided, _reliability, _is_cyclic, + (uint16_t)_eventgroups.size(), _eventgroups); + + if(!its_command.add_registration(reg)) { + VSOMEIP_ERROR << __func__ << ": register event command is too long."; + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + + if (_is_provided) { + VSOMEIP_INFO << "REGISTER EVENT(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _notifier + << ":is_provider=" << std::boolalpha << _is_provided << "]"; + } + } else + VSOMEIP_ERROR << __func__ + << ": register event command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + (void)_client; +#if 0 + VSOMEIP_ERROR << "routing_manager_client::" << __func__ + << "(" << std::hex << std::setw(4) << std::setfill('0') << host_->get_client() << "):" + << "event=" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << _eventgroup << "." + << std::hex << std::setw(4) << std::setfill('0') << _event; +#endif + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto& its_event : its_eventgroup->get_events()) { + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x0 /*OK*/); + } + } + } else { + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } +} + +void routing_manager_client::on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + (void)_client; + if (_event == ANY_EVENT) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + for (const auto& its_event : its_eventgroup->get_events()) { + host_->on_subscription_status(_service, _instance, _eventgroup, its_event->get_event(), 0x7 /*Rejected*/); + } + } + } else { + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x7 /*Rejected*/); + } +} + +void routing_manager_client::cache_event_payload( + const std::shared_ptr<message> &_message) { + const service_t its_service(_message->get_service()); + const instance_t its_instance(_message->get_instance()); + const method_t its_method(_message->get_method()); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + if (its_event->is_field()) { + its_event->prepare_update_payload(_message->get_payload(), true); + its_event->update_payload(); + } + } else { + // we received a event which was not yet requested + std::set<eventgroup_t> its_eventgroups; + // create a placeholder field until someone requests this event with + // full information like eventgroup, field or not etc. + routing_manager_base::register_event(host_->get_client(), + its_service, its_instance, + its_method, + its_eventgroups, event_type_e::ET_UNKNOWN, + reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, + nullptr, + false, false, true); + std::shared_ptr<event> its_event = find_event(its_service, its_instance, its_method); + if (its_event) { + its_event->prepare_update_payload(_message->get_payload(), true); + its_event->update_payload(); + } + } +} + +void routing_manager_client::on_stop_offer_service(service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor) { + (void) _major; + (void) _minor; + std::map<event_t, std::shared_ptr<event> > events; + { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto its_events_service = events_.find(_service); + if (its_events_service != events_.end()) { + auto its_events_instance = its_events_service->second.find(_instance); + if (its_events_instance != its_events_service->second.end()) { + for (auto &e : its_events_instance->second) + events[e.first] = e.second; + } + } + } + for (auto &e : events) { + e.second->unset_payload(); + } +} + +void routing_manager_client::send_pending_commands() { + for (auto &po : pending_offers_) + send_offer_service(get_client(), + po.service_, po.instance_, + po.major_, po.minor_); + + send_pending_event_registrations(get_client()); + + send_request_services(requests_); +} + +void routing_manager_client::init_receiver() { +#ifdef __linux__ + auto its_policy_manager = configuration_->get_policy_manager(); + if (!its_policy_manager) + return; + + its_policy_manager->store_client_to_sec_client_mapping(get_client(), get_sec_client()); + its_policy_manager->store_sec_client_to_client_mapping(get_sec_client(), get_client()); +#endif + if (!receiver_) { + receiver_ = ep_mgr_->create_local_server(shared_from_this()); + } else { + std::uint16_t its_port = receiver_->get_local_port(); + if (its_port != ILLEGAL_PORT) + VSOMEIP_INFO << "Reusing local server endpoint@" << its_port << " endpoint: " << receiver_; + } +} + +void routing_manager_client::notify_remote_initially(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, const std::set<event_t> &_events_to_exclude) { + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + auto service_info = find_service(_service, _instance); + for (const auto &e : its_eventgroup->get_events()) { + if (e->is_field() && e->is_set() + && _events_to_exclude.find(e->get_event()) + == _events_to_exclude.end()) { + std::shared_ptr<message> its_notification + = runtime::get()->create_notification(); + its_notification->set_service(_service); + its_notification->set_instance(_instance); + its_notification->set_method(e->get_event()); + its_notification->set_payload(e->get_payload()); + if (service_info) { + its_notification->set_interface_version(service_info->get_major()); + } + + std::shared_ptr<serializer> its_serializer(get_serializer()); + if (its_serializer->serialize(its_notification.get())) { + { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + send_local(sender_, VSOMEIP_ROUTING_CLIENT, + its_serializer->get_data(), its_serializer->get_size(), + _instance, false, protocol::id_e::NOTIFY_ID, 0); + } + } + its_serializer->reset(); + put_serializer(its_serializer); + } else { + VSOMEIP_ERROR << "Failed to serialize message. Check message size!"; + } + } + } + } + +} + +uint32_t routing_manager_client::get_remote_subscriber_count(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, bool _increment) { + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + uint32_t count (0); + bool found(false); + auto found_service = remote_subscriber_count_.find(_service); + if (found_service != remote_subscriber_count_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_group = found_instance->second.find(_eventgroup); + if (found_group != found_instance->second.end()) { + found = true; + if (_increment) { + found_group->second = found_group->second + 1; + } else { + if (found_group->second > 0) { + found_group->second = found_group->second - 1; + } + } + count = found_group->second; + } + } + } + if (!found) { + if (_increment) { + remote_subscriber_count_[_service][_instance][_eventgroup] = 1; + count = 1; + } + } + return count; +} + +void routing_manager_client::clear_remote_subscriber_count( + service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + auto found_service = remote_subscriber_count_.find(_service); + if (found_service != remote_subscriber_count_.end()) { + if (found_service->second.erase(_instance)) { + if (!found_service->second.size()) { + remote_subscriber_count_.erase(found_service); + } + } + } +} + +void +routing_manager_client::assign_client_timeout_cbk( + boost::system::error_code const &_error) { + + if (!_error) { + bool register_again(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ != inner_state_type_e::ST_REGISTERED) { + state_ = inner_state_type_e::ST_DEREGISTERED; + register_again = true; + } else { + VSOMEIP_INFO << __func__ << ": Will not retry registry for Client [0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << "] : already registered "; + } + } + if (register_again) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + VSOMEIP_WARNING << "Client 0x" << std::hex << std::setw(4) << std::setfill('0') + << get_client() << " request client timeout! Trying again..."; + + if (sender_) { + sender_->restart(); + } + } + } else if (_error != boost::asio::error::operation_aborted) { //ignore error when timer is deliberately cancelled + VSOMEIP_WARNING << __func__ << ": Ignoring Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " due to error_code: " << _error.value() ; + } +} + +void routing_manager_client::register_application_timeout_cbk( + boost::system::error_code const &_error) { + + bool register_again(false); + { + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (!_error && state_ != inner_state_type_e::ST_REGISTERED) { + state_ = inner_state_type_e::ST_DEREGISTERED; + register_again = true; + } + } + if (register_again) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + VSOMEIP_WARNING << std::hex << "Client 0x" + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " register timeout! Trying again..."; + + if (sender_) + sender_->restart(); + } +} + +void routing_manager_client::send_registered_ack() { + + protocol::registered_ack_command its_command; + its_command.set_client(get_client()); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": registered ack command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +bool routing_manager_client::is_client_known(client_t _client) { + + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + return (known_clients_.find(_client) != known_clients_.end()); +} + +bool routing_manager_client::create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _notifier, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client) { + + std::lock_guard<std::mutex> its_lock(stop_mutex_); + + bool is_inserted(false); + + if (find_service(_service, _instance)) { + // We received an event for an existing service which was not yet + // requested/offered. Create a placeholder field until someone + // requests/offers this event with full information like eventgroup, + // field/event, etc. + std::set<eventgroup_t> its_eventgroups({ _eventgroup }); + // routing_manager_client: Always register with own client id and shadow = false + routing_manager_base::register_event(host_->get_client(), + _service, _instance, _notifier, + its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, nullptr, false, false, + true); + + std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier); + if (its_event) { + is_inserted = its_event->add_subscriber(_eventgroup, _filter, _client, false); + } + } + + return is_inserted; +} + +void routing_manager_client::request_debounce_timeout_cbk( + boost::system::error_code const &_error) { + + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (!_error) { + if (requests_to_debounce_.size()) { + if (state_ == inner_state_type_e::ST_REGISTERED) { + send_request_services(requests_to_debounce_); + requests_.insert(requests_to_debounce_.begin(), + requests_to_debounce_.end()); + requests_to_debounce_.clear(); + } else { + { + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + request_debounce_timer_running_ = true; + request_debounce_timer_.expires_from_now(std::chrono::milliseconds( + configuration_->get_request_debouncing(host_->get_name()))); + request_debounce_timer_.async_wait( + std::bind( + &routing_manager_client::request_debounce_timeout_cbk, + std::dynamic_pointer_cast<routing_manager_client>(shared_from_this()), + std::placeholders::_1)); + return; + } + } + } + } + { + std::lock_guard<std::mutex> its_lock(request_timer_mutex_); + request_debounce_timer_running_ = false; + } +} + +void routing_manager_client::register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint) { + + _endpoint->register_error_handler( + std::bind(&routing_manager_client::handle_client_error, this, _client)); +} + +void routing_manager_client::handle_client_error(client_t _client) { + + if (_client != VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_INFO << "rmc::handle_client_error" << "Client 0x" << std::hex << std::setw(4) + << std::setfill('0') << get_client() << " handles a client error(" << std::hex + << std::setw(4) << std::setfill('0') << _client << ") not reconnecting"; + remove_local(_client, true); + } else { + bool should_reconnect(true); + { + std::unique_lock<std::mutex> its_lock(state_mutex_); + should_reconnect = is_started_; + } + if (should_reconnect) { + std::map<client_t, std::string> its_known_clients; + { + std::lock_guard<std::mutex> its_lock(known_clients_mutex_); + its_known_clients = known_clients_; + } + reconnect(its_known_clients); + } + } +} + +void routing_manager_client::send_get_offered_services_info(client_t _client, offer_type_e _offer_type) { + + protocol::offered_services_request_command its_command; + its_command.set_client(_client); + its_command.set_offer_type(_offer_type); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": offered service request command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_unsubscribe_ack( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + remote_subscription_id_t _id) { + + protocol::unsubscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::resend_provided_event_registrations() { + std::lock_guard<std::mutex> its_lock(state_mutex_); + for (const event_data_t& ed : pending_event_registrations_) { + if (ed.is_provided_) { + send_register_event(get_client(), ed.service_, ed.instance_, + ed.notifier_, ed.eventgroups_, ed.type_, ed.reliability_, + ed.is_provided_, ed.is_cyclic_); + } + } +} + +void routing_manager_client::send_resend_provided_event_response(pending_remote_offer_id_t _id) { + + protocol::resend_provided_events_command its_command; + its_command.set_client(get_client()); + its_command.set_remote_offer_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": resend provided event command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +#ifndef VSOMEIP_DISABLE_SECURITY +void routing_manager_client::send_update_security_policy_response( + pending_security_update_id_t _update_id) { + + protocol::update_security_policy_response_command its_command; + its_command.set_client(get_client()); + its_command.set_update_id(_update_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": update security policy response command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::send_remove_security_policy_response( + pending_security_update_id_t _update_id) { + + protocol::remove_security_policy_response_command its_command; + its_command.set_client(get_client()); + its_command.set_update_id(_update_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::lock_guard<std::mutex> its_lock(sender_mutex_); + if (sender_) { + sender_->send(&its_buffer[0], uint32_t(its_buffer.size())); + } + } else + VSOMEIP_ERROR << __func__ + << ": update security policy response command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_client::on_update_security_credentials( + const protocol::update_security_credentials_command &_command) { + + auto its_policy_manager = configuration_->get_policy_manager(); + if (!its_policy_manager) + return; + + for (const auto &c : _command.get_credentials()) { + std::shared_ptr<policy> its_policy(std::make_shared<policy>()); + boost::icl::interval_set<gid_t> its_gid_set; + uid_t its_uid(c.first); + gid_t its_gid(c.second); + + its_gid_set.insert(its_gid); + + its_policy->credentials_ += std::make_pair( + boost::icl::interval<uid_t>::closed(its_uid, its_uid), its_gid_set); + its_policy->allow_who_ = true; + its_policy->allow_what_ = true; + + its_policy_manager->add_security_credentials(its_uid, its_gid, its_policy, get_client()); + } +} +#endif + +void routing_manager_client::on_client_assign_ack(const client_t &_client) { + + std::lock_guard<std::mutex> its_lock(state_mutex_); + if (state_ == inner_state_type_e::ST_ASSIGNING) { + if (_client != VSOMEIP_CLIENT_UNSET) { + state_ = inner_state_type_e::ST_ASSIGNED; + + boost::system::error_code ec; + register_application_timer_.cancel(ec); + host_->set_client(_client); + + if (is_started_) { + init_receiver(); + if (receiver_) { + receiver_->start(); + + VSOMEIP_INFO << "Client " + << std::hex << std::setw(4) << std::setfill('0') << get_client() + << " (" << host_->get_name() << ") successfully connected to routing ~> registering.."; + register_application(); + } else { + VSOMEIP_WARNING << __func__ << ": (" << host_->get_name() << ":" + << std::hex << std::setw(4) << std::setfill('0') + << _client << ") Receiver not started. Restarting"; + state_ = inner_state_type_e::ST_DEREGISTERED; + + host_->set_client(VSOMEIP_CLIENT_UNSET); + + sender_->restart(); + } + } else { + VSOMEIP_WARNING << __func__ << ": (" << host_->get_name() << ":" + << std::hex << std::setw(4) << std::setfill('0') + << _client << ") Not started. Discarding"; + } + } else { + VSOMEIP_ERROR << __func__ << ": (" << host_->get_name() << ":" + << std::hex << std::setw(4) << std::setfill('0') + << _client << ") Invalid clientID"; + } + } else { + VSOMEIP_WARNING << "Client " << std::hex << std::setw(4) << std::setfill('0') + << get_client() << " received another client identifier (" << _client + << "). Ignoring it. (" << static_cast<int>(state_.load()) << ")"; + } +} + +void routing_manager_client::on_suspend() { + + VSOMEIP_INFO << __func__ << ": Application " + << std::hex << std::setw(4) << std::setfill('0') + << host_->get_client(); + + std::lock_guard<std::mutex> its_lock(remote_subscriber_count_mutex_); + + // Unsubscribe everything that is left over. + for (const auto &s : remote_subscriber_count_) { + for (const auto &i : s.second) { + for (const auto &e : i.second) + routing_manager_base::unsubscribe( + VSOMEIP_ROUTING_CLIENT, nullptr, + s.first, i.first, e.first, ANY_EVENT); + } + } + + // Remove all entries. + remote_subscriber_count_.clear(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_impl.cpp new file mode 100644 index 00000000000..9d45c656ace --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_impl.cpp @@ -0,0 +1,5063 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <climits> +#include <iomanip> +#include <memory> +#include <sstream> +#include <forward_list> +#include <thread> + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <unistd.h> +#include <cstdio> +#include <time.h> +#include <inttypes.h> +#endif + +#include <boost/asio/steady_timer.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/event.hpp" +#include "../include/eventgroupinfo.hpp" +#include "../include/remote_subscription.hpp" +#include "../include/routing_manager_host.hpp" +#include "../include/routing_manager_impl.hpp" +#include "../include/routing_manager_stub.hpp" +#include "../include/serviceinfo.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" +#include "../../endpoints/include/tcp_client_endpoint_impl.hpp" +#include "../../endpoints/include/tcp_server_endpoint_impl.hpp" +#include "../../endpoints/include/udp_client_endpoint_impl.hpp" +#include "../../endpoints/include/udp_server_endpoint_impl.hpp" +#include "../../endpoints/include/virtual_server_endpoint_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/message_impl.hpp" +#include "../../message/include/serializer.hpp" +#include "../../plugin/include/plugin_manager_impl.hpp" +#include "../../protocol/include/protocol.hpp" +#include "../../security/include/security.hpp" +#include "../../service_discovery/include/constants.hpp" +#include "../../service_discovery/include/defines.hpp" +#include "../../service_discovery/include/runtime.hpp" +#include "../../service_discovery/include/service_discovery.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif + +#ifndef ANDROID +#include "../../e2e_protection/include/buffer/buffer.hpp" +#include "../../e2e_protection/include/e2exf/config.hpp" + +#include "../../e2e_protection/include/e2e/profile/e2e_provider.hpp" +#endif + +#ifdef USE_DLT +#include "../../tracing/include/connector_impl.hpp" +#endif + +namespace vsomeip_v3 { + +#ifdef ANDROID +namespace sd { +runtime::~runtime() {} +} +#endif + +routing_manager_impl::routing_manager_impl(routing_manager_host *_host) : + routing_manager_base(_host), + version_log_timer_(_host->get_io()), + if_state_running_(false), + sd_route_set_(false), + routing_running_(false), + status_log_timer_(_host->get_io()), + memory_log_timer_(_host->get_io()), + ep_mgr_impl_(std::make_shared<endpoint_manager_impl>(this, io_, configuration_)), + pending_remote_offer_id_(0), + last_resume_(std::chrono::steady_clock::now().min()), + statistics_log_timer_(_host->get_io()), + ignored_statistics_counter_(0) +{ +} + +routing_manager_impl::~routing_manager_impl() { + utility::reset_client_ids(configuration_->get_network()); + utility::remove_lockfile(configuration_->get_network()); +} + +boost::asio::io_context &routing_manager_impl::get_io() { + return routing_manager_base::get_io(); +} + +client_t routing_manager_impl::get_client() const { + return routing_manager_base::get_client(); +} + +const vsomeip_sec_client_t *routing_manager_impl::get_sec_client() const { + + return routing_manager_base::get_sec_client(); +} + +std::string routing_manager_impl::get_client_host() const { + return routing_manager_base::get_client_host(); +} + +void routing_manager_impl::set_client_host(const std::string &_client_host) { + routing_manager_base::set_client_host(_client_host); +} + +std::string routing_manager_impl::get_env(client_t _client) const { + + std::lock_guard<std::mutex> its_known_clients_lock(known_clients_mutex_); + return get_env_unlocked(_client); +} + +std::string routing_manager_impl::get_env_unlocked(client_t _client) const { + + auto find_client = known_clients_.find(_client); + if (find_client != known_clients_.end()) { + return find_client->second; + } + return ""; +} + +std::set<client_t> routing_manager_impl::find_local_clients(service_t _service, instance_t _instance) { + return routing_manager_base::find_local_clients(_service, _instance); +} + +client_t routing_manager_impl::find_local_client(service_t _service, instance_t _instance) { + return routing_manager_base::find_local_client(_service, _instance); +} + +bool routing_manager_impl::is_subscribe_to_any_event_allowed( + const vsomeip_sec_client_t *_sec_client, client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup) { + + return routing_manager_base::is_subscribe_to_any_event_allowed(_sec_client, _client, + _service, _instance, _eventgroup); +} + +void routing_manager_impl::add_known_client(client_t _client, const std::string &_client_host) { + routing_manager_base::add_known_client(_client, _client_host); +} + +bool routing_manager_impl::is_routing_manager() const { + return true; +} + +void routing_manager_impl::init() { + routing_manager_base::init(ep_mgr_impl_); + + if (configuration_->is_routing_enabled()) { + stub_ = std::make_shared<routing_manager_stub>(this, configuration_); + stub_->init(); + } else { + VSOMEIP_INFO << "Internal message routing disabled!"; + } + + if (configuration_->is_sd_enabled()) { + VSOMEIP_INFO<< "Service Discovery enabled. Trying to load module."; + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY); + if (its_plugin) { + VSOMEIP_INFO << "Service Discovery module loaded."; + discovery_ = std::dynamic_pointer_cast<sd::runtime>(its_plugin)->create_service_discovery(this, configuration_); + discovery_->init(); + } else { + VSOMEIP_ERROR << "Service Discovery module could not be loaded!"; + std::exit(EXIT_FAILURE); + } + } + +#ifndef ANDROID + if( configuration_->is_e2e_enabled()) { + VSOMEIP_INFO << "E2E protection enabled."; + + const char *its_e2e_module = getenv(VSOMEIP_ENV_E2E_PROTECTION_MODULE); + std::string plugin_name = its_e2e_module != nullptr ? its_e2e_module : VSOMEIP_E2E_LIBRARY; + + auto its_plugin = plugin_manager::get()->get_plugin(plugin_type_e::APPLICATION_PLUGIN, plugin_name); + if (its_plugin) { + VSOMEIP_INFO << "E2E module loaded."; + e2e_provider_ = std::dynamic_pointer_cast<e2e::e2e_provider>(its_plugin); + } + } + + if(e2e_provider_) { + std::map<e2exf::data_identifier_t, std::shared_ptr<cfg::e2e>> its_e2e_configuration = configuration_->get_e2e_configuration(); + for (auto &identifier : its_e2e_configuration) { + if(!e2e_provider_->add_configuration(identifier.second)) { + VSOMEIP_INFO << "Unknown E2E profile: " << identifier.second->profile << ", skipping ..."; + } + } + } +#endif +} + +void routing_manager_impl::start() { +#if defined(__linux__) || defined(ANDROID) + boost::asio::ip::address its_multicast; + try { + its_multicast = boost::asio::ip::address::from_string(configuration_->get_sd_multicast()); + } catch (...) { + VSOMEIP_ERROR << "Illegal multicast address \"" + << configuration_->get_sd_multicast() + << "\". Please check your configuration."; + } + + std::stringstream its_netmask_or_prefix; + auto its_unicast = configuration_->get_unicast_address(); + if (its_unicast.is_v4()) + its_netmask_or_prefix << "netmask:" << configuration_->get_netmask().to_string(); + else + its_netmask_or_prefix << "prefix:" << configuration_->get_prefix(); + + VSOMEIP_INFO << "Client [" + << std::hex << std::setw(4) << std::setfill('0') + << get_client() + << "] routes unicast:" << its_unicast.to_string() + << ", " + << its_netmask_or_prefix.str(); + + netlink_connector_ = std::make_shared<netlink_connector>( + host_->get_io(), configuration_->get_unicast_address(), its_multicast); + netlink_connector_->register_net_if_changes_handler( + std::bind(&routing_manager_impl::on_net_interface_or_route_state_changed, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + netlink_connector_->start(); +#else + { + std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); + start_ip_routing(); + } +#endif + + if (stub_) + stub_->start(); + host_->on_state(state_type_e::ST_REGISTERED); + + if (configuration_->log_version()) { + std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); + version_log_timer_.expires_from_now( + std::chrono::seconds(0)); + version_log_timer_.async_wait(std::bind(&routing_manager_impl::log_version_timer_cbk, + this, std::placeholders::_1)); + } +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + if (configuration_->log_memory()) { + std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); + boost::system::error_code ec; + memory_log_timer_.expires_from_now(std::chrono::seconds(0), ec); + memory_log_timer_.async_wait( + std::bind(&routing_manager_impl::memory_log_timer_cbk, this, + std::placeholders::_1)); + } +#endif + if (configuration_->log_status()) { + std::lock_guard<std::mutex> its_lock(status_log_timer_mutex_); + boost::system::error_code ec; + status_log_timer_.expires_from_now(std::chrono::seconds(0), ec); + status_log_timer_.async_wait( + std::bind(&routing_manager_impl::status_log_timer_cbk, this, + std::placeholders::_1)); + } + + if (configuration_->log_statistics()) { + std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_); + boost::system::error_code ec; + statistics_log_timer_.expires_from_now(std::chrono::seconds(0), ec); + statistics_log_timer_.async_wait( + std::bind(&routing_manager_impl::statistics_log_timer_cbk, this, + std::placeholders::_1)); + } +} + +void routing_manager_impl::stop() { + // Ensure to StopOffer all services that are offered by the application hosting the rm + local_services_map_t its_services; + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + for (const auto& s : local_services_) { + for (const auto& i : s.second) { + if (std::get<2>(i.second) == get_client()) { + its_services[s.first][i.first] = i.second; + } + } + } + + } + for (const auto& s : its_services) { + for (const auto& i : s.second) { + on_stop_offer_service(std::get<2>(i.second), s.first, i.first, + std::get<0>(i.second), std::get<1>(i.second)); + } + } + + { + std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); + version_log_timer_.cancel(); + } +#if defined(__linux__) || defined(ANDROID) + { + boost::system::error_code ec; + std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); + memory_log_timer_.cancel(ec); + } + if (netlink_connector_) { + netlink_connector_->stop(); + } +#endif + + { + std::lock_guard<std::mutex> its_lock(status_log_timer_mutex_); + boost::system::error_code ec; + status_log_timer_.cancel(ec); + } + + { + std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_); + boost::system::error_code ec; + statistics_log_timer_.cancel(ec); + } + + host_->on_state(state_type_e::ST_DEREGISTERED); + + if (discovery_) + discovery_->stop(); + if (stub_) + stub_->stop(); + + for (const auto client : ep_mgr_->get_connected_clients()) { + if (client != VSOMEIP_ROUTING_CLIENT) { + remove_local(client, true); + } + } +} + +bool routing_manager_impl::insert_offer_command(service_t _service, instance_t _instance, uint8_t _command, + client_t _client, major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> its_lock(offer_serialization_mutex_); + // flag to indicate whether caller of this function can start directly processing the command + bool must_process(false); + auto found_service_instance = offer_commands_.find(std::make_pair(_service, _instance)); + if (found_service_instance != offer_commands_.end()) { + // if nothing is queued + if (found_service_instance->second.empty()) { + must_process = true; + } + found_service_instance->second.push_back( + std::make_tuple(_command, _client, _major, _minor)); + } else { + // nothing is queued -> add command to queue and process command directly + offer_commands_[std::make_pair(_service, _instance)].push_back( + std::make_tuple(_command, _client, _major, _minor)); + must_process = true; + } + return must_process; +} + +bool routing_manager_impl::erase_offer_command(service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(offer_serialization_mutex_); + auto found_service_instance = offer_commands_.find(std::make_pair(_service, _instance)); + if (found_service_instance != offer_commands_.end()) { + // erase processed command + if (!found_service_instance->second.empty()) { + found_service_instance->second.pop_front(); + if (!found_service_instance->second.empty()) { + // check for other commands to be processed + auto its_command = found_service_instance->second.front(); + if (std::get<0>(its_command) == uint8_t(protocol::id_e::OFFER_SERVICE_ID)) { + io_.post([&, its_command, _service, _instance](){ + offer_service(std::get<1>(its_command), _service, _instance, + std::get<2>(its_command), std::get<3>(its_command), false); + }); + } else { + io_.post([&, its_command, _service, _instance](){ + stop_offer_service(std::get<1>(its_command), _service, _instance, + std::get<2>(its_command), std::get<3>(its_command), false); + }); + } + } + } + } + return true; +} + +bool routing_manager_impl::offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + return offer_service(_client, _service, _instance, _major, _minor, true); +} + +bool routing_manager_impl::offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _must_queue) { + + // only queue commands if method was NOT called via erase_offer_command() + if (_must_queue) { + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::OFFER_SERVICE_ID), + _client, _major, _minor)) { + VSOMEIP_INFO << "rmi::" << __func__ << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << ":" << std::dec << int(_major) << "." << std::dec << _minor << "]" + << " (" << std::boolalpha << _must_queue << ")" + << " not offering service, because insert_offer_command returned false!"; + return false; + } + } + + // Check if the application hosted by routing manager is allowed to offer + // offer_service requests of local proxies are checked in rms::on:message + if (_client == get_client()) { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_offer( + get_sec_client(), _service, _instance)) { + VSOMEIP_WARNING << "routing_manager_impl::offer_service: " + << std::hex << "Security: Client 0x" << _client + << " isn't allowed to offer the following service/instance " + << _service << "/" << _instance + << " ~> Skip offer!"; + erase_offer_command(_service, _instance); + return false; + } + } + + if (!handle_local_offer_service(_client, _service, _instance, _major, _minor)) { + erase_offer_command(_service, _instance); + VSOMEIP_INFO << __func__ << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << ":" << std::dec << int(_major) << "." << std::dec << _minor << "]" + << " (" << std::boolalpha << _must_queue << ")" + << " not offering, returned from handle_local_offer_service!"; + return false; + } + + { + std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); + if (if_state_running_) { + init_service_info(_service, _instance, true); + } else { + pending_sd_offers_.push_back(std::make_pair(_service, _instance)); + } + } + + if (discovery_) { + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + if (its_info) { + discovery_->offer_service(its_info); + } + } + + { + std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); + std::set<event_t> its_already_subscribed_events; + for (auto &ps : pending_subscriptions_) { + if (ps.service_ == _service + && ps.instance_ == _instance + && ps.major_ == _major) { + insert_subscription(ps.service_, ps.instance_, + ps.eventgroup_, ps.event_, nullptr, + get_client(), &its_already_subscribed_events); +#if 0 + VSOMEIP_ERROR << __func__ + << ": event=" + << std::hex << ps.service_ << "." + << std::hex << ps.instance_ << "." + << std::hex << ps.event_; +#endif + } + } + + send_pending_subscriptions(_service, _instance, _major); + } + if (stub_) + stub_->on_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_AVAILABLE, _major, _minor); + erase_offer_command(_service, _instance); + + VSOMEIP_INFO << "OFFER(" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << ":" << std::dec << int(_major) << "." << std::dec << _minor << "]" + << " (" << std::boolalpha << _must_queue << ")"; + + return true; +} + +void routing_manager_impl::stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + stop_offer_service(_client, _service, _instance, _major, _minor, true); +} + +void routing_manager_impl::stop_offer_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _must_queue) { + + VSOMEIP_INFO << "STOP OFFER(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance + << ":" << std::dec << int(_major) << "." << _minor << "]" + << " (" << std::boolalpha << _must_queue << ")"; + + if (_must_queue) { + if (!insert_offer_command(_service, _instance, + uint8_t(protocol::id_e::STOP_OFFER_SERVICE_ID), + _client, _major, _minor)) { + VSOMEIP_INFO << "rmi::" << __func__ << " (" + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << ":" << std::dec << int(_major) << "." << _minor << "]" + << " (" << std::boolalpha << _must_queue << ")" + << " STOP-OFFER NOT INSERTED!"; + return; + } + } + + bool is_local(false); + { + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + is_local = (its_info && its_info->is_local()); + } + if (is_local) { + { + std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); + for (auto it = pending_sd_offers_.begin(); it != pending_sd_offers_.end(); ) { + if (it->first == _service && it->second == _instance) { + it = pending_sd_offers_.erase(it); + break; + } else { + ++it; + } + } + } + + on_stop_offer_service(_client, _service, _instance, _major, _minor); + if (stub_) + stub_->on_stop_offer_service(_client, _service, _instance, _major, _minor); + on_availability(_service, _instance, availability_state_e::AS_UNAVAILABLE, _major, _minor); + } else { + VSOMEIP_WARNING << __func__ << " received STOP_OFFER(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance + << ":" << std::dec << int(_major) << "." << _minor << "] " + << "for remote service --> ignore"; + erase_offer_command(_service, _instance); + } +} + +void routing_manager_impl::request_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + + VSOMEIP_INFO << "REQUEST(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << ":" + << std::dec << int(_major) << "." << _minor << "]"; + + routing_manager_base::request_service(_client, + _service, _instance, _major, _minor); + + auto its_info = find_service(_service, _instance); + if (!its_info) { + add_requested_service(_client, _service, _instance, _major, _minor); + if (discovery_) { + if (!configuration_->is_local_service(_service, _instance)) { + // Non local service instance ~> tell SD to find it! + discovery_->request_service(_service, _instance, _major, _minor, + DEFAULT_TTL); + } else { + VSOMEIP_INFO << std::hex + << "Avoid trigger SD find-service message" + << " for local service/instance/major/minor: " + << _service << "/" << _instance << std::dec + << "/" << (uint32_t)_major << "/" << _minor; + } + } + } else { + if ((_major == its_info->get_major() + || DEFAULT_MAJOR == its_info->get_major() + || ANY_MAJOR == _major) + && (_minor <= its_info->get_minor() + || DEFAULT_MINOR == its_info->get_minor() + || _minor == ANY_MINOR)) { + if(!its_info->is_local()) { + add_requested_service(_client, _service, _instance, _major, _minor); + if (discovery_) { + // Non local service instance ~> tell SD to find it! + discovery_->request_service(_service, _instance, _major, + _minor, DEFAULT_TTL); + } + its_info->add_client(_client); + ep_mgr_impl_->find_or_create_remote_client(_service, _instance); + } + } + } + + if (_client == get_client()) { + if (stub_) + stub_->create_local_receiver(); + + protocol::service its_request(_service, _instance, _major, _minor); + std::set<protocol::service> requests; + requests.insert(its_request); + + if (stub_) + stub_->handle_requests(_client, requests); + } +} + +void routing_manager_impl::release_service(client_t _client, service_t _service, + instance_t _instance) { + + VSOMEIP_INFO << "RELEASE(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "]"; + + if (host_->get_client() == _client) { + std::lock_guard<std::mutex> its_lock(pending_subscription_mutex_); + remove_pending_subscription(_service, _instance, 0xFFFF, ANY_EVENT); + } + routing_manager_base::release_service(_client, _service, _instance); + remove_requested_service(_client, _service, _instance, ANY_MAJOR, ANY_MINOR); + + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if (its_info && !its_info->is_local()) { + if (0 == its_info->get_requesters_size()) { + auto its_eventgroups = find_eventgroups(_service, _instance); + for (const auto &eg : its_eventgroups) { + auto its_events = eg->get_events(); + for (auto &e : its_events) { + e->clear_subscribers(); + } + } + + if (discovery_) { + discovery_->release_service(_service, _instance); + discovery_->unsubscribe_all(_service, _instance); + } + ep_mgr_impl_->clear_client_endpoints(_service, _instance, true); + ep_mgr_impl_->clear_client_endpoints(_service, _instance, false); + its_info->set_endpoint(nullptr, true); + its_info->set_endpoint(nullptr, false); + unset_all_eventpayloads(_service, _instance); + } else { + auto its_eventgroups = find_eventgroups(_service, _instance); + for (const auto &eg : its_eventgroups) { + auto its_id = eg->get_eventgroup(); + auto its_events = eg->get_events(); + bool eg_has_subscribers{false}; + for (const auto &e : its_events) { + e->remove_subscriber(its_id, _client); + if (!e->get_subscribers().empty()) { + eg_has_subscribers = true; + } + } + if (discovery_) { + discovery_->unsubscribe(_service, _instance, its_id, _client); + } + if (!eg_has_subscribers) { + for (const auto &e : its_events) { + e->unset_payload(true); + } + } + } + } + } else { + if (discovery_) { + discovery_->release_service(_service, _instance); + } + } +} + +void routing_manager_impl::subscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) { + + if (routing_state_ == routing_state_e::RS_SUSPENDED) { + VSOMEIP_INFO << "rmi::" << __func__ << " We are suspended --> do nothing."; + return; + } + + VSOMEIP_INFO << "SUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << ":" + << std::setw(4) << _event << ":" + << std::dec << (uint16_t)_major << "]"; + const client_t its_local_client = find_local_client(_service, _instance); + if (get_client() == its_local_client) { +#ifdef VSOMEIP_ENABLE_COMPAT + routing_manager_base::set_incoming_subscription_state(_client, _service, _instance, + _eventgroup, _event, subscription_state_e::IS_SUBSCRIBING); +#endif + auto self = shared_from_this(); + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), true, + [this, self, _client, _sec_client, _service, _instance, _eventgroup, + _major, _event, _filter] + (const bool _subscription_accepted) { + (void) ep_mgr_->find_or_create_local(_client); + if (!_subscription_accepted) { + if (stub_) + stub_->send_subscribe_nack(_client, _service, _instance, _eventgroup, _event); + VSOMEIP_INFO << "Subscription request from client: 0x" << std::hex + << _client << std::dec << " for eventgroup: 0x" << _eventgroup + << " rejected from application handler."; + return; + } else if (stub_) { + stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); + } + routing_manager_base::subscribe(_client, _sec_client, + _service, _instance, _eventgroup, _major, + _event, _filter); +#ifdef VSOMEIP_ENABLE_COMPAT + send_pending_notify_ones(_service, _instance, _eventgroup, _client); + routing_manager_base::erase_incoming_subscription_state(_client, _service, _instance, + _eventgroup, _event); +#endif + }); + } else { + if (discovery_) { + std::set<event_t> its_already_subscribed_events; + + // Note: The calls to insert_subscription & handle_subscription_state must not + // run concurrently to a call to on_subscribe_ack. Therefore the lock is acquired + // before calling insert_subscription and released after the call to + // handle_subscription_state. + std::unique_lock<std::mutex> its_critical(remote_subscription_state_mutex_); + bool inserted = insert_subscription(_service, _instance, _eventgroup, + _event, _filter, _client, &its_already_subscribed_events); + const bool subscriber_is_rm_host = (get_client() == _client); + if (inserted) { + if (0 == its_local_client) { + handle_subscription_state(_client, _service, _instance, _eventgroup, _event); + its_critical.unlock(); + static const ttl_t configured_ttl(configuration_->get_sd_ttl()); + notify_one_current_value(_client, _service, _instance, + _eventgroup, _event, its_already_subscribed_events); + + auto its_info = find_eventgroup(_service, _instance, _eventgroup); + // if the subscriber is the rm_host itself: check if service + // is available before subscribing via SD otherwise we sent + // a StopSubscribe/Subscribe once the first offer is received + if (its_info && + (!subscriber_is_rm_host || find_service(_service, _instance))) { + discovery_->subscribe(_service, _instance, _eventgroup, + _major, configured_ttl, + its_info->is_selective() ? _client : VSOMEIP_ROUTING_CLIENT, + its_info); + } + } else { + its_critical.unlock(); + if (is_available(_service, _instance, _major) && stub_) { + stub_->send_subscribe(ep_mgr_->find_local(_service, _instance), + _client, _service, _instance, _eventgroup, _major, + _event, _filter, PENDING_SUBSCRIPTION_ID); + } + } + } + if (subscriber_is_rm_host) { + std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); + subscription_data_t subscription = { + _service, _instance, + _eventgroup, _major, + _event, _filter, + *_sec_client + }; + pending_subscriptions_.insert(subscription); + } + } else { + VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!"; + } + } +} + +void routing_manager_impl::unsubscribe( + client_t _client, const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event) { + + VSOMEIP_INFO << "UNSUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]"; + + bool last_subscriber_removed(true); + + std::shared_ptr<eventgroupinfo> its_info + = find_eventgroup(_service, _instance, _eventgroup); + if (its_info) { + for (const auto& e : its_info->get_events()) { + if (e->get_event() == _event || ANY_EVENT == _event) + e->remove_subscriber(_eventgroup, _client); + } + for (const auto& e : its_info->get_events()) { + if (e->has_subscriber(_eventgroup, ANY_CLIENT)) { + last_subscriber_removed = false; + break; + } + } + } + + if (discovery_) { + host_->on_subscription(_service, _instance, _eventgroup, _client, + _sec_client, get_env(_client), false, + [](const bool _subscription_accepted){ (void)_subscription_accepted; }); + if (0 == find_local_client(_service, _instance)) { + if (get_client() == _client) { + std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); + remove_pending_subscription(_service, _instance, _eventgroup, _event); + } + if (last_subscriber_removed) { + unset_all_eventpayloads(_service, _instance, _eventgroup); + { + auto tuple = std::make_tuple(_service, _instance, _eventgroup, _client); + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + remote_subscription_state_.erase(tuple); + } + } + + if (its_info && + (last_subscriber_removed || its_info->is_selective())) { + + discovery_->unsubscribe(_service, _instance, _eventgroup, + its_info->is_selective() ? _client : VSOMEIP_ROUTING_CLIENT); + } + } else { + if (get_client() == _client) { + std::lock_guard<std::mutex> ist_lock(pending_subscription_mutex_); + remove_pending_subscription(_service, _instance, _eventgroup, _event); + if (stub_) + stub_->send_unsubscribe( + ep_mgr_->find_local(_service, _instance), + _client, _service, _instance, _eventgroup, _event, + PENDING_SUBSCRIPTION_ID); + } + } + ep_mgr_impl_->clear_multicast_endpoints(_service, _instance); + + } else { + VSOMEIP_ERROR<< "SOME/IP eventgroups require SD to be enabled!"; + } +} + +bool routing_manager_impl::send(client_t _client, + std::shared_ptr<message> _message, bool _force) { + + return routing_manager_base::send(_client, _message, _force); +} + +bool routing_manager_impl::send(client_t _client, const byte_t *_data, + length_t _size, instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _sent_from_remote, bool _force) { + + bool is_sent(false); + if (_size > VSOMEIP_MESSAGE_TYPE_POS) { + std::shared_ptr<endpoint> its_target; + bool is_request = utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS]); + bool is_notification = utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS]); + bool is_response = utility::is_response(_data[VSOMEIP_MESSAGE_TYPE_POS]); + client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + client_t its_target_client = get_client(); + + bool is_service_discovery + = (its_service == sd::service && its_method == sd::method); + + if (is_request) { + its_target_client = find_local_client(its_service, _instance); + its_target = find_local(its_target_client); + } else if (!is_notification) { + its_target = find_local(its_client); + its_target_client = its_client; + } else if (is_notification && _client + && !is_service_discovery) { // Selective notifications! + if (_client == get_client()) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(its_target, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#endif + deliver_message(_data, _size, _instance, _reliable, + _bound_client, _sec_client, + _status_check, _sent_from_remote); + return true; + } + its_target = find_local(_client); + its_target_client = _client; + } + + if (its_target) { +#ifdef USE_DLT + if ((is_request && its_client == get_client()) || + (is_response && find_local_client(its_service, _instance) == get_client()) || + (is_notification && find_local_client(its_service, _instance) == VSOMEIP_ROUTING_CLIENT)) { + + trace::header its_header; + if (its_header.prepare(its_target, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif + is_sent = send_local(its_target, its_target_client, _data, _size, _instance, _reliable, + protocol::id_e::SEND_ID, _status_check); + } else { + // Check whether hosting application should get the message + // If not, check routes to external + if ((its_client == host_->get_client() && is_response) + || (find_local_client(its_service, _instance) + == host_->get_client() && is_request)) { + // TODO: Find out how to handle session id here + is_sent = deliver_message(_data, _size, _instance, _reliable, + VSOMEIP_ROUTING_CLIENT, _sec_client, _status_check); + } else { + e2e_buffer its_buffer; + + if (e2e_provider_) { + if ( !is_service_discovery) { + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); +#ifndef ANDROID + if (e2e_provider_->is_protected({its_service, its_method})) { + // Find out where the protected area starts + size_t its_base = e2e_provider_->get_protection_base({its_service, its_method}); + + // Build a corresponding buffer + its_buffer.assign(_data + its_base, _data + _size); + + e2e_provider_->protect({ its_service, its_method }, its_buffer, _instance); + + // Prepend header + its_buffer.insert(its_buffer.begin(), _data, _data + its_base); + + _data = its_buffer.data(); + } +#endif + } + } + if (is_request) { + its_target = ep_mgr_impl_->find_or_create_remote_client( + its_service, _instance, _reliable); + if (its_target) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(its_target, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#endif + is_sent = its_target->send(_data, _size); + } else { + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_ERROR<< "Routing info for remote service could not be found! (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_method << "] " + << std::setw(4) << its_session; + } + } else { + std::shared_ptr<serviceinfo> its_info(find_service(its_service, _instance)); + if (its_info || is_service_discovery) { + if (is_notification && !is_service_discovery) { + (void)send_local_notification(get_client(), _data, _size, _instance, + _reliable, _status_check, _force); + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method); + if (its_event) { +#ifdef USE_DLT + bool has_sent(false); +#endif + std::set<std::shared_ptr<endpoint_definition>> its_targets; + // we need both endpoints as clients can subscribe to events via TCP and UDP + std::shared_ptr<endpoint> its_udp_server_endpoint = its_info->get_endpoint(false); + std::shared_ptr<endpoint> its_tcp_server_endpoint = its_info->get_endpoint(true); + + if (its_udp_server_endpoint || its_tcp_server_endpoint) { + const auto its_reliability = its_event->get_reliability(); + for (auto its_group : its_event->get_eventgroups()) { + auto its_eventgroup = find_eventgroup(its_service, _instance, its_group); + if (its_eventgroup) { + // Unicast targets + for (const auto &its_remote : its_eventgroup->get_unicast_targets()) { + if (its_remote->is_reliable() && its_tcp_server_endpoint) { + if (its_reliability == reliability_type_e::RT_RELIABLE + || its_reliability == reliability_type_e::RT_BOTH) { + its_targets.insert(its_remote); + } + } else if (its_udp_server_endpoint && !its_eventgroup->is_sending_multicast()) { + if (its_reliability == reliability_type_e::RT_UNRELIABLE + || its_reliability == reliability_type_e::RT_BOTH) { + its_targets.insert(its_remote); + } + } + } + // Send to multicast targets if subscribers are still interested + if (its_eventgroup->is_sending_multicast()) { + if (its_reliability == reliability_type_e::RT_UNRELIABLE + || its_reliability == reliability_type_e::RT_BOTH) { + boost::asio::ip::address its_address; + uint16_t its_port; + if (its_eventgroup->get_multicast(its_address, its_port)) { + std::shared_ptr<endpoint_definition> its_multicast_target; + its_multicast_target = endpoint_definition::get(its_address, + its_port, false, its_service, _instance); + its_targets.insert(its_multicast_target); + } + } + } + } + } + } + + for (auto const &target : its_targets) { + if (target->is_reliable()) { + its_tcp_server_endpoint->send_to(target, _data, _size); + } else { + its_udp_server_endpoint->send_to(target, _data, _size); + } +#ifdef USE_DLT + has_sent = true; +#endif + } +#ifdef USE_DLT + if (has_sent) { + trace::header its_header; + if (its_header.prepare(nullptr, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif + } + } else { + if ((utility::is_response(_data[VSOMEIP_MESSAGE_TYPE_POS]) + || utility::is_error(_data[VSOMEIP_MESSAGE_TYPE_POS])) + && !its_info->is_local()) { + // We received a response/error but neither the hosting application + // nor another local client could be found --> drop + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_ERROR + << "routing_manager_impl::send: Received response/error for unknown client (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_method << "] " + << std::setw(4) << its_session; + return false; + } + its_target = is_service_discovery ? + (sd_info_ ? sd_info_->get_endpoint(false) : nullptr) : its_info->get_endpoint(_reliable); + if (its_target) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(its_target, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#endif + is_sent = its_target->send(_data, _size); + } else { + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_ERROR << "Routing error. Endpoint for service (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_method << "] " + << std::setw(4) << its_session + << " could not be found!"; + } + } + } else { + if (!is_notification) { + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + VSOMEIP_ERROR << "Routing error. Not hosting service (" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_method << "] " + << std::setw(4) << its_session; + } + } + } + } + } + } + + return is_sent; +} + +bool routing_manager_impl::send_to( + const client_t _client, + const std::shared_ptr<endpoint_definition> &_target, + std::shared_ptr<message> _message) { + + bool is_sent(false); + + std::shared_ptr<serializer> its_serializer(get_serializer()); + if (its_serializer->serialize(_message.get())) { + const byte_t *its_data = its_serializer->get_data(); + length_t its_size = its_serializer->get_size(); + e2e_buffer its_buffer; + if (e2e_provider_) { + service_t its_service = bithelper::read_uint16_be(&its_data[VSOMEIP_SERVICE_POS_MIN]); + method_t its_method = bithelper::read_uint16_be(&its_data[VSOMEIP_METHOD_POS_MIN]); +#ifndef ANDROID + if (e2e_provider_->is_protected({its_service, its_method})) { + auto its_base = e2e_provider_->get_protection_base({its_service, its_method}); + its_buffer.assign(its_data + its_base, its_data + its_size); + e2e_provider_->protect({its_service, its_method}, its_buffer, _message->get_instance()); + its_buffer.insert(its_buffer.begin(), its_data, its_data + its_base); + its_data = its_buffer.data(); + } +#endif + } + + uint8_t its_client[2] = {0}; + bithelper::write_uint16_le(_client, its_client); + const_cast<byte_t*>(its_data)[VSOMEIP_CLIENT_POS_MIN] = its_client[1]; + const_cast<byte_t*>(its_data)[VSOMEIP_CLIENT_POS_MAX] = its_client[0]; + + is_sent = send_to(_target, its_data, its_size, _message->get_instance()); + + its_serializer->reset(); + put_serializer(its_serializer); + } else { + VSOMEIP_ERROR<< "routing_manager_impl::send_to: serialization failed."; + } + return is_sent; +} + +bool routing_manager_impl::send_to( + const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, instance_t _instance) { + + std::shared_ptr<endpoint> its_endpoint = + ep_mgr_impl_->find_server_endpoint( + _target->get_remote_port(), _target->is_reliable()); + + if (its_endpoint) { +#ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(its_endpoint, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); +#else + (void) _instance; +#endif + return its_endpoint->send_to(_target, _data, _size); + } + return false; +} + +bool routing_manager_impl::send_via_sd( + const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port) { + std::shared_ptr<endpoint> its_endpoint = + ep_mgr_impl_->find_server_endpoint(_sd_port, + _target->is_reliable()); + + if (its_endpoint) { +#ifdef USE_DLT + if (tc_->is_sd_enabled()) { + trace::header its_header; + if (its_header.prepare(its_endpoint, true, 0x0)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + + } +#endif + return its_endpoint->send_to(_target, _data, _size); + } + + return false; +} + +void routing_manager_impl::register_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, const event_type_e _type, + reliability_type_e _reliability, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + epsilon_change_func_t _epsilon_change_func, + bool _is_provided, bool _is_shadow, bool _is_cache_placeholder) { + auto its_event = find_event(_service, _instance, _notifier); + bool is_first(false); + if (its_event) { + if (!its_event->has_ref(_client, _is_provided)) { + is_first = true; + } + } else { + is_first = true; + } + if (is_first) { + routing_manager_base::register_event(_client, + _service, _instance, + _notifier, + _eventgroups, _type, _reliability, + _cycle, _change_resets_cycle, _update_on_change, + _epsilon_change_func, _is_provided, _is_shadow, + _is_cache_placeholder); + } + VSOMEIP_INFO << "REGISTER EVENT(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _notifier + << ":is_provider=" << std::boolalpha << _is_provided << "]"; +} + +void routing_manager_impl::register_shadow_event(client_t _client, + service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, event_type_e _type, + reliability_type_e _reliability, bool _is_provided, bool _is_cyclic) { + + routing_manager_base::register_event(_client, + _service, _instance, + _notifier, + _eventgroups, _type, _reliability, + (_is_cyclic ? std::chrono::milliseconds(1) + : std::chrono::milliseconds::zero()), + false, true, nullptr, + _is_provided, true); +} + +void routing_manager_impl::unregister_shadow_event(client_t _client, + service_t _service, instance_t _instance, + event_t _event, bool _is_provided) { + routing_manager_base::unregister_event(_client, _service, _instance, + _event, _is_provided); +} + +void routing_manager_impl::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, client_t _client, + bool _force +#ifdef VSOMEIP_ENABLE_COMPAT + , bool _remote_subscriber +#endif + ) { + if (find_local(_client)) { + routing_manager_base::notify_one(_service, _instance, _event, _payload, + _client, _force +#ifdef VSOMEIP_ENABLE_COMPAT + , _remote_subscriber +#endif + ); + } else { + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + std::set<std::shared_ptr<endpoint_definition> > its_targets; + const auto its_reliability = its_event->get_reliability(); + for (const auto g : its_event->get_eventgroups()) { + const auto its_eventgroup = find_eventgroup(_service, _instance, g); + if (its_eventgroup) { + const auto its_subscriptions = its_eventgroup->get_remote_subscriptions(); + for (const auto &s : its_subscriptions) { + if (s->has_client(_client)) { + if (its_reliability == reliability_type_e::RT_RELIABLE + || its_reliability == reliability_type_e::RT_BOTH) { + const auto its_reliable = s->get_reliable(); + if (its_reliable) + its_targets.insert(its_reliable); + } + if (its_reliability == reliability_type_e::RT_UNRELIABLE + || its_reliability == reliability_type_e::RT_BOTH) { + const auto its_unreliable = s->get_unreliable(); + if (its_unreliable) + its_targets.insert(its_unreliable); + } + } + } + } + } + + if (its_targets.size() > 0) { + for (const auto &its_target : its_targets) { + its_event->set_payload(_payload, _client, its_target, _force); + } + } + } else { + VSOMEIP_WARNING << "Attempt to update the undefined event/field [" + << std::hex << _service << "." << _instance << "." << _event + << "]"; + } + } +} + +void routing_manager_impl::on_availability(service_t _service, instance_t _instance, + availability_state_e _state, major_version_t _major, minor_version_t _minor) { + // insert subscriptions of routing manager into service discovery + // to send SubscribeEventgroup after StopOffer / Offer was received + if (_state == availability_state_e::AS_AVAILABLE) { + if (discovery_) { + const client_t its_local_client = find_local_client(_service, _instance); + // remote service + if (VSOMEIP_ROUTING_CLIENT == its_local_client) { + static const ttl_t configured_ttl(configuration_->get_sd_ttl()); + std::lock_guard<std::recursive_mutex> its_subscribed_lock(discovery_->get_subscribed_mutex()); + std::lock_guard<std::mutex> its_lock(pending_subscription_mutex_); + for (auto &ps : pending_subscriptions_) { + if (ps.service_ == _service + && ps.instance_ == _instance + && ps.major_ == _major) { + auto its_info = find_eventgroup(_service, _instance, ps.eventgroup_); + if (its_info) { + discovery_->subscribe( + _service, + _instance, + ps.eventgroup_, + _major, + configured_ttl, + its_info->is_selective() ? get_client() : VSOMEIP_ROUTING_CLIENT, + its_info); + } + } + } + } + } + } + host_->on_availability(_service, _instance, _state, _major, _minor); +} + + +bool routing_manager_impl::offer_service_remotely(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = true; + + if(!is_available(_service, _instance, ANY_MAJOR)) { + VSOMEIP_ERROR << __func__ << ": Service [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance + << "] is not offered locally! Won't offer it remotely."; + ret = false; + } else { + // update service info in configuration + if (!configuration_->remote_offer_info_add(_service, _instance, _port, + _reliable, _magic_cookies_enabled)) { + ret = false; + } else { + // trigger event registration again to create shadow events + const client_t its_offering_client = find_local_client(_service, _instance); + if (its_offering_client == VSOMEIP_ROUTING_CLIENT) { + VSOMEIP_ERROR << __func__ << " didn't find offering client for service [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance + << "]"; + ret = false; + } else { + if (stub_ && !stub_->send_provided_event_resend_request(its_offering_client, + pending_remote_offer_add(_service, _instance))) { + VSOMEIP_ERROR << __func__ << ": Couldn't send event resend" + << std::hex << std::setfill('0') + << "request to client 0x" << std::setw(4) << its_offering_client + << " providing service [" << std::setw(4) << _service << "." + << std::setw(4) << _instance + << "]"; + + ret = false; + } + } + } + } + return ret; +} + +bool routing_manager_impl::stop_offer_service_remotely(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled) { + bool ret = true; + bool service_still_offered_remote(false); + // update service configuration + if (!configuration_->remote_offer_info_remove(_service, _instance, _port, + _reliable, _magic_cookies_enabled, &service_still_offered_remote)) { + VSOMEIP_ERROR << __func__ << " couldn't remove remote offer info for service [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance + << "] from configuration"; + ret = false; + } + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + std::shared_ptr<endpoint> its_server_endpoint; + if (its_info) { + its_server_endpoint = its_info->get_endpoint(_reliable); + } + // don't deregister events if the service is still offered remotely + if (!service_still_offered_remote) { + const client_t its_offering_client = find_local_client(_service, _instance); + major_version_t its_major(0); + minor_version_t its_minor(0); + if (its_info) { + its_major = its_info->get_major(); + its_minor = its_info->get_minor(); + } + // unset payload and clear subcribers + routing_manager_base::stop_offer_service(its_offering_client, + _service, _instance, its_major, its_minor); + // unregister events + for (const event_t its_event_id : find_events(_service, _instance)) { + unregister_shadow_event(its_offering_client, _service, _instance, + its_event_id, true); + } + clear_targets_and_pending_sub_from_eventgroups(_service, _instance); + clear_remote_subscriber(_service, _instance); + + if (discovery_ && its_info) { + discovery_->stop_offer_service(its_info, true); + its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); + } + } else { + // service is still partly offered + if (discovery_ && its_info) { + std::shared_ptr<serviceinfo> its_copied_info = + std::make_shared<serviceinfo>(*its_info); + its_info->set_endpoint(std::shared_ptr<endpoint>(), _reliable); + // ensure to not send StopOffer for endpoint on which the service is + // still offered + its_copied_info->set_endpoint(std::shared_ptr<endpoint>(), !_reliable); + discovery_->stop_offer_service(its_copied_info, true); + VSOMEIP_INFO << __func__ << " only sending the StopOffer to [" + << std::hex << std::setw(4) << std::setfill('0') << _service << '.' + << std::hex << std::setw(4) << std::setfill('0') << _instance << ']' + << " with reliability (" << std::boolalpha << !_reliable << ')' + << " as the service is still partly offered!"; + } + } + + cleanup_server_endpoint(_service, its_server_endpoint); + return ret; +} + +void routing_manager_impl::on_message(const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { +#if 0 + std::stringstream msg; + msg << "rmi::on_message: "; + for (uint32_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + (void)_bound_client; + service_t its_service; + method_t its_method; + uint8_t its_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + instance_t its_instance(0x0); + message_type_e its_message_type; +#ifdef USE_DLT + bool is_forwarded(true); +#endif + if (_size >= VSOMEIP_SOMEIP_HEADER_SIZE) { + its_message_type = static_cast<message_type_e>(_data[VSOMEIP_MESSAGE_TYPE_POS]); + its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + if (its_service == VSOMEIP_SD_SERVICE) { + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + if (discovery_ && its_method == sd::method) { + if (configuration_->get_sd_port() == _remote_port) { + if (!_remote_address.is_unspecified()) { + // ACL check SD message + if(!is_acl_message_allowed(_receiver, its_service, ANY_INSTANCE, _remote_address)) { + return; + } + discovery_->on_message(_data, _size, _remote_address, _is_multicast); + } else { + VSOMEIP_ERROR << "Ignored SD message from unknown address."; + } + } else { + VSOMEIP_ERROR << "Ignored SD message from unknown port (" + << _remote_port << ")"; + } + } + } else { + if (_is_multicast) { + its_instance = ep_mgr_impl_->find_instance_multicast(its_service, _remote_address); + } else { + its_instance = ep_mgr_impl_->find_instance(its_service, _receiver); + } + if (its_instance == 0xFFFF) { + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + const client_t its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + const session_t its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + boost::system::error_code ec; + VSOMEIP_ERROR << "Received message on invalid port: [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_method << "." + << std::setw(4) << its_client << "." + << std::setw(4) << its_session << "] from: " + << _remote_address.to_string(ec) << ":" << std::dec << _remote_port; + } + //Ignore messages with invalid message type + if(_size >= VSOMEIP_MESSAGE_TYPE_POS) { + if(!utility::is_valid_message_type(its_message_type)) { + VSOMEIP_ERROR << "Ignored SomeIP message with invalid message type."; + return; + } + } + return_code_e return_code = check_error(_data, _size, its_instance); + if(!(_size >= VSOMEIP_MESSAGE_TYPE_POS && utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]))) { + if (return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) { + send_error(return_code, _data, _size, its_instance, + _receiver->is_reliable(), _receiver, + _remote_address, _remote_port); + return; + } + } else if(return_code != return_code_e::E_OK && return_code != return_code_e::E_NOT_OK) { + //Ignore request no response message if an error occured + return; + } + + // Security checks if enabled! + if (configuration_->is_security_enabled()) { + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + client_t requester = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + if (!configuration_->is_offered_remote(its_service, its_instance)) { + VSOMEIP_WARNING << std::hex << "Security: Received a remote request " + << "for service/instance " << its_service << "/" << its_instance + << " which isn't offered remote ~> Skip message!"; + return; + } + if (find_local(requester)) { + VSOMEIP_WARNING << std::hex << "Security: Received a remote request " + << "from client identifier 0x" << requester + << " which is already used locally ~> Skip message!"; + return; + } + if (!configuration_->is_remote_access_allowed()) { + // check if policy allows remote requests. + VSOMEIP_WARNING << "routing_manager_impl::on_message: " + << std::hex << "Security: Remote client with client ID 0x" << requester + << " is not allowed to communicate with service/instance/method " + << its_service << "/" << its_instance + << "/" << its_method; + return; + } + } + } + if (e2e_provider_) { + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); +#ifndef ANDROID + if (e2e_provider_->is_checked({its_service, its_method})) { + auto its_base = e2e_provider_->get_protection_base({its_service, its_method}); + e2e_buffer its_buffer(_data + its_base, _data + _size); + e2e_provider_->check({its_service, its_method}, + its_buffer, its_instance, its_check_status); + + if (its_check_status != e2e::profile_interface::generic_check_status::E2E_OK) { + VSOMEIP_INFO << "E2E protection: CRC check failed for service: " + << std::hex << its_service << " method: " << its_method; + } + } +#endif + } + + // ACL check message + if(!is_acl_message_allowed(_receiver, its_service, its_instance, _remote_address)) { + return; + } + + // Common way of message handling +#ifdef USE_DLT + is_forwarded = +#endif + on_message(its_service, its_instance, _data, _size, _receiver->is_reliable(), + _bound_client, _sec_client, its_check_status, true); + } + } +#ifdef USE_DLT + if (is_forwarded) { + trace::header its_header; + const boost::asio::ip::address_v4 its_remote_address = + _remote_address.is_v4() ? _remote_address.to_v4() : + boost::asio::ip::address_v4::from_string("6.6.6.6"); + trace::protocol_e its_protocol = + _receiver->is_local() ? trace::protocol_e::local : + _receiver->is_reliable() ? trace::protocol_e::tcp : + trace::protocol_e::udp; + its_header.prepare(its_remote_address, _remote_port, its_protocol, false, + its_instance); + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + } +#endif +} + +bool routing_manager_impl::on_message(service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _check_status, bool _is_from_remote) { +#if 0 + std::stringstream msg; + msg << "rmi::on_message(" + << std::hex << std::setw(4) << std::setfill('0') + << _service << ", " << _instance << "): "; + for (uint32_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + client_t its_client; + bool is_forwarded(true); + + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + its_client = find_local_client(_service, _instance); + } else { + its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + } + +#if 0 + // ACL message check for local test purpouse + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + if (its_info) { + std::shared_ptr<endpoint> _receiver = its_info->get_endpoint(_reliable); + if (_receiver && _receiver.get()) { + if(!is_acl_message_allowed(_receiver.get(), _service, _instance, + boost::asio::ip::address_v4::from_string("127.0.0.1"))) { + return false; + } + } + } +#endif + + if (utility::is_notification(_data[VSOMEIP_MESSAGE_TYPE_POS])) { + is_forwarded = deliver_notification(_service, _instance, _data, _size, + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); + } else if (its_client == host_->get_client()) { + deliver_message(_data, _size, _instance, + _reliable, _bound_client, _sec_client, _check_status, _is_from_remote); + } else { + send(its_client, _data, _size, _instance, _reliable, + _bound_client, _sec_client, _check_status, _is_from_remote, false); //send to proxy + } + return is_forwarded; +} + +void routing_manager_impl::on_notification(client_t _client, + service_t _service, instance_t _instance, + const byte_t *_data, length_t _size, bool _notify_one) { + event_t its_event_id = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + std::shared_ptr<event> its_event = find_event(_service, _instance, its_event_id); + if (its_event) { + uint32_t its_length = utility::get_payload_size(_data, _size); + std::shared_ptr<payload> its_payload = + runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], + its_length); + + if (_notify_one) { + notify_one(_service, _instance, its_event->get_event(), + its_payload, _client, true +#ifdef VSOMEIP_ENABLE_COMPAT + , false +#endif + ); + } else { + if (its_event->is_field()) { + if (!its_event->set_payload_notify_pending(its_payload)) { + its_event->set_payload(its_payload, false); + } + } else { + its_event->set_payload(its_payload, VSOMEIP_ROUTING_CLIENT, true); + } + } + } +} + +void routing_manager_impl::on_stop_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_.find(_service); + if (found_service != local_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if ( std::get<0>(found_instance->second) != _major + || std::get<1>(found_instance->second) != _minor + || std::get<2>(found_instance->second) != _client) { + VSOMEIP_WARNING + << "routing_manager_impl::on_stop_offer_service: " + << "trying to delete service not matching exactly " + << "the one offered previously: " << "[" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << _instance << "." << std::dec << static_cast<std::uint32_t>(_major) + << "." << _minor << "] by application: " + << std::hex + << std::setw(4) << _client << ". Stored: [" + << std::setw(4) << _service + << "." << _instance << "." + << std::dec + << static_cast<std::uint32_t>(std::get<0>(found_instance->second)) << "." + << std::get<1>(found_instance->second) + << "] by application: " + << std::hex + << std::setw(4) << std::get<2>(found_instance->second); + } + if (std::get<2>(found_instance->second) == _client) { + found_service->second.erase(_instance); + if (found_service->second.size() == 0) { + local_services_.erase(_service); + } + } + } + } + } + + routing_manager_base::stop_offer_service(_client, _service, _instance, + _major, _minor); + + /** + * Hold reliable & unreliable server-endpoints from service info + * because if "del_routing_info" is called those entries could be freed + * and we can't be sure this happens synchronous when SD is active. + * After triggering "del_routing_info" this endpoints gets cleanup up + * within this method if they not longer used by any other local service. + */ + std::shared_ptr<endpoint> its_reliable_endpoint; + std::shared_ptr<endpoint> its_unreliable_endpoint; + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if (its_info) { + its_reliable_endpoint = its_info->get_endpoint(true); + its_unreliable_endpoint = its_info->get_endpoint(false); + + // Create a ready_to_stop_t object to synchronize the stopping + // of the service on reliable and unreliable endpoints. + struct ready_to_stop_t { + ready_to_stop_t(bool _reliable, bool _unreliable) + : reliable_(_reliable), unreliable_(_unreliable) { + } + + inline bool is_ready() const { + return reliable_ && unreliable_; + } + + std::atomic<bool> reliable_; + std::atomic<bool> unreliable_; + }; + auto ready_to_stop = std::make_shared<ready_to_stop_t>( + its_reliable_endpoint == nullptr, its_unreliable_endpoint == nullptr); + auto ptr = shared_from_this(); + + auto callback = [this, ptr, its_info, its_reliable_endpoint, its_unreliable_endpoint, + ready_to_stop, _service, _instance, _major, _minor] + (std::shared_ptr<endpoint> _endpoint) { + + if (its_reliable_endpoint && its_reliable_endpoint == _endpoint) + ready_to_stop->reliable_ = true; + + if (its_unreliable_endpoint && its_unreliable_endpoint == _endpoint) + ready_to_stop->unreliable_ = true; + + if (discovery_) { + if (its_info->get_major() == _major && its_info->get_minor() == _minor) + discovery_->stop_offer_service(its_info, true); + } + del_routing_info(_service, _instance, + its_reliable_endpoint != nullptr, its_unreliable_endpoint != nullptr); + + for (const auto& ep: {its_reliable_endpoint, its_unreliable_endpoint}) { + if (ep) { + if (ep_mgr_impl_->remove_instance(_service, ep.get())) { + // last instance -> pass ANY_INSTANCE and shutdown completely + ep->prepare_stop( + [this, ptr] (std::shared_ptr<endpoint> _endpoint_to_stop) { + if (ep_mgr_impl_->remove_server_endpoint( + _endpoint_to_stop->get_local_port(), + _endpoint_to_stop->is_reliable())) { + _endpoint_to_stop->stop(); + } + }, ANY_SERVICE); + } + // Clear service info and service group + clear_service_info(_service, _instance, ep->is_reliable()); + } + } + + if (ready_to_stop->is_ready()) + erase_offer_command(_service, _instance); + }; + + for (const auto& ep : { its_reliable_endpoint, its_unreliable_endpoint }) { + if (ep) + ep->prepare_stop(callback, _service); + } + + if (!its_reliable_endpoint && !its_unreliable_endpoint) { + erase_offer_command(_service, _instance); + } + + std::set<std::shared_ptr<eventgroupinfo> > its_eventgroup_info_set; + { + std::lock_guard<std::mutex> its_eventgroups_lock(eventgroups_mutex_); + auto find_service = eventgroups_.find(_service); + if (find_service != eventgroups_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + for (auto e : find_instance->second) { + its_eventgroup_info_set.insert(e.second); + } + } + } + } + + for (auto e : its_eventgroup_info_set) { + e->clear_remote_subscriptions(); + } + } else { + erase_offer_command(_service, _instance); + } +} + +bool routing_manager_impl::deliver_message(const byte_t *_data, length_t _size, + instance_t _instance, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _is_from_remote) { + + bool is_delivered(false); + + auto its_deserializer = get_deserializer(); + its_deserializer->set_data(_data, _size); + std::shared_ptr<message_impl> its_message(its_deserializer->deserialize_message()); + its_deserializer->reset(); + put_deserializer(its_deserializer); + + if (its_message) { + its_message->set_instance(_instance); + its_message->set_reliable(_reliable); + its_message->set_check_result(_status_check); + if (_sec_client) + its_message->set_sec_client(*_sec_client); + its_message->set_env(get_env(_bound_client)); + + if (!_is_from_remote) { + if (utility::is_notification(its_message->get_message_type())) { + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << std::hex << " received a notification from client 0x" << _bound_client + << " which does not offer service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return false; + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return false; + } + } + } else if (utility::is_request(its_message->get_message_type())) { + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && its_message->get_client() != _bound_client) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message:" + << " received a request from client 0x" << std::setw(4) << std::setfill('0') + << its_message->get_client() << " to service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() << " which doesn't match the bound client 0x" + << std::setw(4) << _bound_client + << " ~> Skip message!"; + return false; + } + + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << " isn't allowed to send a request to service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return false; + } + } else { // response + if (!is_response_allowed(_bound_client, its_message->get_service(), + its_message->get_instance(), its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << " received a response from client 0x" << _bound_client + << " which does not offer service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " ~> Skip message!"; + return false; + } else { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << " isn't allowed to receive a response from service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from client 0x" << _bound_client + << " ~> Skip message!"; + return false; + } + } + } + } else { + if (!configuration_->is_remote_access_allowed()) { + // if the message is from remote, check if + // policy allows remote requests. + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << std::hex << "Remote clients are not allowed" + << " to communicate with service/instance/method " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively with client 0x" << get_client() + << " ~> Skip message!"; + return false; + } else if (utility::is_notification(its_message->get_message_type())) { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + get_sec_client(), its_message->get_service(), its_message->get_instance(), + its_message->get_method())) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_impl::deliver_message: " + << " isn't allowed to receive a notification from service/instance/event " + << its_message->get_service() << "/" << its_message->get_instance() + << "/" << its_message->get_method() + << " respectively from remote client" + << " ~> Skip message!"; + return false; + } + } + } + + host_->on_message(std::move(its_message)); + is_delivered = true; + } else { + VSOMEIP_ERROR << "Routing manager: deliver_message: " + << "SomeIP-Header deserialization failed!"; + } + return is_delivered; +} + +#ifdef VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING +bool +routing_manager_impl::has_subscribed_eventgroup( + service_t _service, instance_t _instance) const { + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) + for (const auto &its_eventgroup : found_instance->second) + for (const auto &e : its_eventgroup.second->get_events()) + if (!e->get_subscribers().empty()) + return true; + } + + return false; +} +#endif // VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING + +bool routing_manager_impl::deliver_notification( + service_t _service, instance_t _instance, + const byte_t *_data, length_t _length, bool _reliable, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + uint8_t _status_check, bool _is_from_remote) { + + event_t its_event_id = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + client_t its_client_id = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + + std::shared_ptr<event> its_event = find_event(_service, _instance, its_event_id); + if (its_event) { + if (!its_event->is_provided()) { + if (its_event->get_subscribers().size() == 0) { + // no subscribers for this specific event / check subscriptions + // to other events of the event's eventgroups + bool cache_event = false; + for (const auto eg : its_event->get_eventgroups()) { + std::shared_ptr<eventgroupinfo> egi = find_eventgroup(_service, _instance, eg); + if (egi) { + for (const auto &e : egi->get_events()) { + cache_event = (e->get_subscribers().size() > 0); + if (cache_event) { + break; + } + } + if (cache_event) { + break; + } + } + } + if (!cache_event) { + VSOMEIP_WARNING << __func__ << ": dropping [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_event_id + << "]. No subscription to corresponding eventgroup."; + return true; // as there is nothing to do + } + } + } + + auto its_length = utility::get_payload_size(_data, _length); + auto its_payload = runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], its_length); + + // incoming events statistics + (void) insert_event_statistics( + _service, _instance, its_event_id, its_length); + + // Ignore the filter for messages coming from other local clients + // as the filter was already applied there. + auto its_subscribers + = its_event->update_and_get_filtered_subscribers(its_payload, _is_from_remote); + if (its_event->get_type() != event_type_e::ET_SELECTIVE_EVENT) { + for (const auto its_local_client : its_subscribers) { + if (its_local_client == host_->get_client()) { + deliver_message(_data, _length, _instance, _reliable, + _bound_client, _sec_client, _status_check, _is_from_remote); + } else { + std::shared_ptr<endpoint> its_local_target = find_local(its_local_client); + if (its_local_target) { + send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, _data, _length, + _instance, _reliable, protocol::id_e::SEND_ID, _status_check); + } + } + } + } else { + // TODO: Check whether it makes more sense to set the client id + // for internal selective events. This would create some extra + // effort but we could avoid this hack. + if (its_client_id == VSOMEIP_ROUTING_CLIENT) + its_client_id = get_client(); + + if (its_subscribers.find(its_client_id) != its_subscribers.end()) { + if (its_client_id == host_->get_client()) { + deliver_message(_data, _length, _instance, _reliable, + _bound_client, _sec_client, _status_check, _is_from_remote); + } else { + std::shared_ptr<endpoint> its_local_target = find_local(its_client_id); + if (its_local_target) { + send_local(its_local_target, VSOMEIP_ROUTING_CLIENT, + _data, _length, _instance, _reliable, protocol::id_e::SEND_ID, _status_check); + } + } + } + } + + } else { +#ifdef VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING + if (has_subscribed_eventgroup(_service, _instance)) { + if (!is_suppress_event(_service, _instance, its_event_id)) { + VSOMEIP_WARNING << __func__ << ": Caching unregistered event [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event_id << "]"; + } + + routing_manager_base::register_event(host_->get_client(), + _service, _instance, its_event_id, { }, + event_type_e::ET_UNKNOWN, + _reliable ? reliability_type_e::RT_RELIABLE + : reliability_type_e::RT_UNRELIABLE, + std::chrono::milliseconds::zero(), false, true, nullptr, + true, true, true); + + its_event = find_event(_service, _instance, its_event_id); + if (its_event) { + auto its_length = utility::get_payload_size(_data, _length); + auto its_payload = runtime::get()->create_payload( + &_data[VSOMEIP_PAYLOAD_POS], its_length); + its_event->set_payload(its_payload, true); + } else + VSOMEIP_ERROR << __func__ << ": Event registration failed [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event_id << "]"; + } else if (!is_suppress_event(_service, _instance, its_event_id)) { + VSOMEIP_WARNING << __func__ << ": Dropping unregistered event [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event_id << "] " + << "Service has no subscribed eventgroup."; + } +#else + if (!is_suppress_event(_service, _instance, its_event_id)) { + VSOMEIP_WARNING << __func__ << ": Event [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance << "." + << std::hex << std::setw(4) << std::setfill('0') << its_event_id << "]" + << " is not registered. The message is dropped."; + } +#endif // VSOMEIP_ENABLE_DEFAULT_EVENT_CACHING + } + return true; +} + +bool routing_manager_impl::is_suppress_event(service_t _service, + instance_t _instance, event_t _event) const { + bool status = configuration_->check_suppress_events(_service, _instance, _event); + + return status; +} + +std::shared_ptr<eventgroupinfo> routing_manager_impl::find_eventgroup( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup) const { + return routing_manager_base::find_eventgroup(_service, _instance, _eventgroup); +} + +std::shared_ptr<endpoint> routing_manager_impl::create_service_discovery_endpoint( + const std::string &_address, uint16_t _port, bool _reliable) { + std::shared_ptr<endpoint> its_service_endpoint = + ep_mgr_impl_->find_server_endpoint(_port, _reliable); + if (!its_service_endpoint) { + try { + its_service_endpoint = + ep_mgr_impl_->create_server_endpoint(_port, + _reliable, true); + + if (its_service_endpoint) { + sd_info_ = std::make_shared<serviceinfo>( + VSOMEIP_SD_SERVICE, VSOMEIP_SD_INSTANCE, + ANY_MAJOR, ANY_MINOR, DEFAULT_TTL, + false); // false, because we do _not_ want to announce it... + sd_info_->set_endpoint(its_service_endpoint, _reliable); + its_service_endpoint->add_default_target(VSOMEIP_SD_SERVICE, + _address, _port); + if (!_reliable) { + auto its_server_endpoint = std::dynamic_pointer_cast< + udp_server_endpoint_impl>(its_service_endpoint); + if (its_server_endpoint) { + its_server_endpoint->set_unicast_sent_callback( + std::bind(&sd::service_discovery::sent_messages, discovery_.get(), + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + its_server_endpoint->set_receive_own_multicast_messages(true); + its_server_endpoint->set_sent_multicast_received_callback( + std::bind(&sd::service_discovery::sent_messages, discovery_.get(), + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + its_server_endpoint->join(_address); + } + } + } else { + VSOMEIP_ERROR<< "Service Discovery endpoint could not be created. " + "Please check your network configuration."; + } + } catch (const std::exception &e) { + VSOMEIP_ERROR << "Server endpoint creation failed: Service " + "Discovery endpoint could not be created: " << e.what(); + } + } + return its_service_endpoint; +} + +services_t routing_manager_impl::get_offered_services() const { + services_t its_services; + for (const auto& s : get_services()) { + for (const auto& i : s.second) { + if (i.second) { + if (i.second->is_local()) { + its_services[s.first][i.first] = i.second; + } + } else { + VSOMEIP_ERROR << __func__ << "Found instance with NULL ServiceInfo [" + << std::hex << std::setw(4) << std::setfill('0') << s.first + << ":" << i.first <<"]"; + } + } + } + return its_services; +} + +std::shared_ptr<serviceinfo> routing_manager_impl::get_offered_service( + service_t _service, instance_t _instance) const { + std::shared_ptr<serviceinfo> its_info; + its_info = find_service(_service, _instance); + if (its_info && !its_info->is_local()) { + its_info.reset(); + } + return its_info; +} + +std::map<instance_t, std::shared_ptr<serviceinfo>> +routing_manager_impl::get_offered_service_instances(service_t _service) const { + std::map<instance_t, std::shared_ptr<serviceinfo>> its_instances; + const services_t its_services(get_services()); + const auto found_service = its_services.find(_service); + if (found_service != its_services.end()) { + for (const auto& i : found_service->second) { + if (i.second->is_local()) { + its_instances[i.first] = i.second; + } + } + } + return its_instances; +} + +bool routing_manager_impl::is_acl_message_allowed(endpoint *_receiver, + service_t _service, instance_t _instance, + const boost::asio::ip::address &_remote_address) const { + if (message_acceptance_handler_ && _receiver) { + // Check the ACL whitelist rules if shall accepts the message + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + const bool is_local = its_info && its_info->is_local(); + + message_acceptance_t message_acceptance { + _remote_address.to_v4().to_uint(), + _receiver->get_local_port(), is_local, _service, _instance + }; + if (!message_acceptance_handler_(message_acceptance)) { + VSOMEIP_WARNING << "Message from " << _remote_address.to_string() + << std::hex << " with service/instance " << _instance << "/" + << _instance << " was rejected by the ACL check."; + return false; + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE +/////////////////////////////////////////////////////////////////////////////// +void routing_manager_impl::init_service_info( + service_t _service, instance_t _instance, bool _is_local_service) { + std::shared_ptr<serviceinfo> its_info = find_service(_service, _instance); + if (!its_info) { + VSOMEIP_ERROR << "routing_manager_impl::init_service_info: couldn't " + "find serviceinfo for service: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "]" + << " is_local_service=" << _is_local_service; + return; + } + if (configuration_) { + // Create server endpoints for local services only + if (_is_local_service) { + const bool is_someip = configuration_->is_someip(_service, _instance); + uint16_t its_reliable_port = configuration_->get_reliable_port( + _service, _instance); + bool _is_found(false); + if (ILLEGAL_PORT != its_reliable_port) { + std::shared_ptr<endpoint> its_reliable_endpoint = + ep_mgr_impl_->find_or_create_server_endpoint( + its_reliable_port, true, is_someip, _service, + _instance, _is_found); + if (its_reliable_endpoint) { + its_info->set_endpoint(its_reliable_endpoint, true); + } + } + uint16_t its_unreliable_port = configuration_->get_unreliable_port( + _service, _instance); + if (ILLEGAL_PORT != its_unreliable_port) { + std::shared_ptr<endpoint> its_unreliable_endpoint = + ep_mgr_impl_->find_or_create_server_endpoint( + its_unreliable_port, false, is_someip, _service, + _instance, _is_found); + if (its_unreliable_endpoint) { + its_info->set_endpoint(its_unreliable_endpoint, false); + } + } + + if (ILLEGAL_PORT == its_reliable_port + && ILLEGAL_PORT == its_unreliable_port) { + VSOMEIP_INFO << "Port configuration missing for [" + << std::hex << _service << "." << _instance + << "]. Service is internal."; + } + } + } else { + VSOMEIP_ERROR << "Missing vsomeip configuration."; + } +} + +void routing_manager_impl::remove_local(client_t _client, bool _remove_uid) { + auto clients_subscriptions = get_subscriptions(_client); + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + for (const auto& s : clients_subscriptions) { + remote_subscription_state_.erase(std::tuple_cat(s, std::make_tuple(_client))); + } + } + routing_manager_base::remove_local(_client, clients_subscriptions, _remove_uid); + + for (const auto &s : get_requested_services(_client)) { + release_service(_client, s.first, s.second); + } +} + +bool routing_manager_impl::is_field(service_t _service, instance_t _instance, + event_t _event) const { + std::lock_guard<std::mutex> its_lock(events_mutex_); + auto find_service = events_.find(_service); + if (find_service != events_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + auto find_event = find_instance->second.find(_event); + if (find_event != find_instance->second.end()) + return find_event->second->is_field(); + } + } + return false; +} + +//only called from the SD +void routing_manager_impl::add_routing_info( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, ttl_t _ttl, + const boost::asio::ip::address &_reliable_address, + uint16_t _reliable_port, + const boost::asio::ip::address &_unreliable_address, + uint16_t _unreliable_port) { + + std::lock_guard<std::mutex> its_lock(routing_state_mutex_); + if (routing_state_ == routing_state_e::RS_SUSPENDED) { + VSOMEIP_INFO << "rmi::" << __func__ << " We are suspended --> do nothing."; + return; + } + + // Create/Update service info + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if (!its_info) { + boost::asio::ip::address its_unicast_address + = configuration_->get_unicast_address(); + bool is_local(false); + if (_reliable_port != ILLEGAL_PORT + && its_unicast_address == _reliable_address) + is_local = true; + else if (_unreliable_port != ILLEGAL_PORT + && its_unicast_address == _unreliable_address) + is_local = true; + + its_info = create_service_info(_service, _instance, _major, _minor, _ttl, is_local); + init_service_info(_service, _instance, is_local); + } else if (its_info->is_local()) { + // We received a service info for a service which is already offered locally + VSOMEIP_ERROR << "routing_manager_impl::add_routing_info: " + << "rejecting routing info. Remote: " + << ((_reliable_port != ILLEGAL_PORT) ? _reliable_address.to_string() + : _unreliable_address.to_string()) << " is trying to offer [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(_major) << "." << _minor + << "] on port " << ((_reliable_port != ILLEGAL_PORT) ? _reliable_port + : _unreliable_port) << " offered previously on this node: [" + << std::hex + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(its_info->get_major()) + << "." << its_info->get_minor() << "]"; + return; + } else { + its_info->set_ttl(_ttl); + } + + // Check whether remote services are unchanged + bool is_reliable_known(false); + bool is_unreliable_known(false); + ep_mgr_impl_->is_remote_service_known(_service, _instance, _major, + _minor, _reliable_address, _reliable_port, &is_reliable_known, + _unreliable_address, _unreliable_port, &is_unreliable_known); + + bool udp_inserted(false); + bool tcp_inserted(false); + // Add endpoint(s) if necessary + if (_reliable_port != ILLEGAL_PORT && !is_reliable_known) { + std::shared_ptr<endpoint_definition> endpoint_def_tcp + = endpoint_definition::get(_reliable_address, _reliable_port, true, _service, _instance); + if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) { + std::shared_ptr<endpoint_definition> endpoint_def_udp + = endpoint_definition::get(_unreliable_address, _unreliable_port, false, _service, _instance); + ep_mgr_impl_->add_remote_service_info(_service, _instance, + endpoint_def_tcp, endpoint_def_udp); + udp_inserted = true; + tcp_inserted = true; + } else { + ep_mgr_impl_->add_remote_service_info(_service, _instance, + endpoint_def_tcp); + tcp_inserted = true; + } + + // check if service was requested and establish TCP connection if necessary + { + bool connected(false); + std::lock_guard<std::mutex> its_lock(requested_services_mutex_); + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + if (!connected) { + if (udp_inserted) { + // atomically create reliable and unreliable endpoint + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance); + } else { + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); + } + connected = true; + } + its_info->add_client(its_client); + } + } + } else if (_reliable_port != ILLEGAL_PORT && is_reliable_known) { + std::lock_guard<std::mutex> its_lock(requested_services_mutex_); + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(true); + if (ep) { + if (ep->is_established() && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + discovery_->on_endpoint_connected( + _service, _instance, ep); + } + } + } else { + // no endpoint yet, but requested -> create one + + // SWS_SD_00376 establish TCP connection to service + // service is marked as available later in on_connect() + ep_mgr_impl_->find_or_create_remote_client( + _service, _instance, true); + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + its_info->add_client(its_client); + } + } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, + its_info->get_major(), its_info->get_minor()); + } + } + + if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) { + if (!udp_inserted) { + std::shared_ptr<endpoint_definition> endpoint_def + = endpoint_definition::get(_unreliable_address, _unreliable_port, false, _service, _instance); + ep_mgr_impl_->add_remote_service_info(_service, _instance, endpoint_def); + // check if service was requested and increase requester count if necessary + { + bool connected(false); + std::lock_guard<std::mutex> its_lock(requested_services_mutex_); + for (const client_t its_client : get_requesters_unlocked( + _service, _instance, _major, _minor)) { + if (!connected) { + ep_mgr_impl_->find_or_create_remote_client(_service, _instance, + false); + connected = true; + } + its_info->add_client(its_client); + } + } + } + if (!is_reliable_known && !tcp_inserted) { + // UDP only service can be marked as available instantly + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, _major, _minor); + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); + } + } + if (discovery_) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); + if (ep && ep->is_established()) { + discovery_->on_endpoint_connected(_service, _instance, ep); + } + } + } else if (_unreliable_port != ILLEGAL_PORT && is_unreliable_known) { + std::lock_guard<std::mutex> its_lock(requested_services_mutex_); + if (has_requester_unlocked(_service, _instance, _major, _minor)) { + if (_reliable_port == ILLEGAL_PORT && !is_reliable_known && + stub_ && + !stub_->contained_in_routing_info( + VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), + its_info->get_minor())) { + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + its_info->get_major(), its_info->get_minor()); + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, + _service, _instance, + its_info->get_major(), + its_info->get_minor()); + if (discovery_) { + std::shared_ptr<endpoint> ep = its_info->get_endpoint(false); + if (ep && ep->is_established()) { + discovery_->on_endpoint_connected( + _service, _instance, + ep); + } + } + } + } else { + on_availability(_service, _instance, + availability_state_e::AS_OFFERED, _major, _minor); + } + } +} + +void routing_manager_impl::del_routing_info(service_t _service, instance_t _instance, + bool _has_reliable, bool _has_unreliable) { + + std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); + if(!its_info) + return; + + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, + its_info->get_major(), its_info->get_minor()); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + its_info->get_major(), its_info->get_minor()); + // Implicit unsubscribe + + std::vector<std::shared_ptr<event>> its_events; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto &its_eventgroup : found_instance->second) { + // As the service is gone, all subscriptions to its events + // do no longer exist and the last received payload is no + // longer valid. + for (auto &its_event : its_eventgroup.second->get_events()) { + const auto its_subscribers = its_event->get_subscribers(); + for (const auto its_subscriber : its_subscribers) { + if (its_subscriber != get_client()) { + its_event->remove_subscriber( + its_eventgroup.first, its_subscriber); + } + } + its_events.push_back(its_event); + } + } + } + } + } + for (const auto& e : its_events) { + e->unset_payload(true); + } + + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + std::set<std::tuple< + service_t, instance_t, eventgroup_t, client_t> > its_invalid; + + for (const auto &its_state : remote_subscription_state_) { + if (std::get<0>(its_state.first) == _service + && std::get<1>(its_state.first) == _instance) { + its_invalid.insert(its_state.first); + } + } + + for (const auto &its_key : its_invalid) + remote_subscription_state_.erase(its_key); + } + + { + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + auto found_service = remote_subscribers_.find(_service); + if (found_service != remote_subscribers_.end()) { + if (found_service->second.erase(_instance) > 0 && + !found_service->second.size()) { + remote_subscribers_.erase(found_service); + } + } + } + + if (_has_reliable) { + ep_mgr_impl_->clear_client_endpoints(_service, _instance, true); + ep_mgr_impl_->clear_remote_service_info(_service, _instance, true); + } + if (_has_unreliable) { + ep_mgr_impl_->clear_client_endpoints(_service, _instance, false); + ep_mgr_impl_->clear_remote_service_info(_service, _instance, false); + } + + ep_mgr_impl_->clear_multicast_endpoints(_service, _instance); + + if (_has_reliable) + clear_service_info(_service, _instance, true); + if (_has_unreliable) + clear_service_info(_service, _instance, false); + + // For expired services using only unreliable endpoints that have never been created before + if (!_has_reliable && !_has_unreliable) { + ep_mgr_impl_->clear_remote_service_info(_service, _instance, true); + ep_mgr_impl_->clear_remote_service_info(_service, _instance, false); + clear_service_info(_service, _instance, true); + clear_service_info(_service, _instance, false); + } +} + +void routing_manager_impl::update_routing_info(std::chrono::milliseconds _elapsed) { + std::map<service_t, std::vector<instance_t> > its_expired_offers; + + { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + for (const auto &s : services_remote_) { + for (const auto &i : s.second) { + ttl_t its_ttl = i.second->get_ttl(); + if (its_ttl < DEFAULT_TTL) { // do not touch "forever" + std::chrono::milliseconds precise_ttl = i.second->get_precise_ttl(); + if (precise_ttl.count() < _elapsed.count() || precise_ttl.count() == 0) { + i.second->set_ttl(0); + its_expired_offers[s.first].push_back(i.first); + } else { + std::chrono::milliseconds its_new_ttl(precise_ttl - _elapsed); + i.second->set_precise_ttl(its_new_ttl); + } + } + } + } + } + + for (const auto &s : its_expired_offers) { + for (const auto &i : s.second) { + if (discovery_) { + discovery_->unsubscribe_all(s.first, i); + } + del_routing_info(s.first, i, true, true); + VSOMEIP_INFO << "update_routing_info: elapsed=" << _elapsed.count() + << " : delete service/instance " + << std::hex << std::setfill('0') + << std::setw(4) << s.first << "." << std::setw(4) << i; + } + } +} + +void routing_manager_impl::expire_services( + const boost::asio::ip::address &_address) { + expire_services(_address, configuration::port_range_t(ANY_PORT, ANY_PORT), + false); +} + +void routing_manager_impl::expire_services( + const boost::asio::ip::address &_address, std::uint16_t _port, + bool _reliable) { + expire_services(_address, configuration::port_range_t(_port, _port), + _reliable); +} + +void routing_manager_impl::expire_services( + const boost::asio::ip::address &_address, + const configuration::port_range_t& _range, bool _reliable) { + std::map<service_t, std::vector<instance_t> > its_expired_offers; + + const bool expire_all = (_range.first == ANY_PORT + && _range.second == ANY_PORT); + + for (auto &s : get_services_remote()) { + for (auto &i : s.second) { + boost::asio::ip::address its_address; + std::shared_ptr<client_endpoint> its_client_endpoint = + std::dynamic_pointer_cast<client_endpoint>( + i.second->get_endpoint(_reliable)); + if (!its_client_endpoint && expire_all) { + its_client_endpoint = std::dynamic_pointer_cast<client_endpoint>( + i.second->get_endpoint(!_reliable)); + } + if (its_client_endpoint) { + if ((expire_all || (its_client_endpoint->get_remote_port() >= _range.first + && its_client_endpoint->get_remote_port() <= _range.second)) + && its_client_endpoint->get_remote_address(its_address) + && its_address == _address) { + if (discovery_) { + discovery_->unsubscribe_all(s.first, i.first); + } + its_expired_offers[s.first].push_back(i.first); + } + } + } + } + + for (auto &s : its_expired_offers) { + for (auto &i : s.second) { + VSOMEIP_INFO << "expire_services for address: " << _address + << " : delete service/instance " + << std::hex << std::setfill('0') + << std::setw(4) << s.first << "." << std::setw(4) << i + << " port [" << std::dec << _range.first << "," << _range.second + << "] reliability=" << std::boolalpha << _reliable; + del_routing_info(s.first, i, true, true); + } + } +} + +void +routing_manager_impl::expire_subscriptions( + const boost::asio::ip::address &_address) { + expire_subscriptions(_address, + configuration::port_range_t(ANY_PORT, ANY_PORT), false); +} + +void +routing_manager_impl::expire_subscriptions( + const boost::asio::ip::address &_address, std::uint16_t _port, + bool _reliable) { + expire_subscriptions(_address, configuration::port_range_t(_port, _port), + _reliable); +} + +void +routing_manager_impl::expire_subscriptions( + const boost::asio::ip::address &_address, + const configuration::port_range_t& _range, bool _reliable) { + const bool expire_all = (_range.first == ANY_PORT + && _range.second == ANY_PORT); + + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<eventgroupinfo> > > >its_eventgroups; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + its_eventgroups = eventgroups_; + } + for (const auto &its_service : its_eventgroups) { + for (const auto &its_instance : its_service.second) { + for (const auto &its_eventgroup : its_instance.second) { + const auto its_info = its_eventgroup.second; + for (auto its_subscription + : its_info->get_remote_subscriptions()) { + if (its_subscription->is_forwarded()) { + VSOMEIP_WARNING << __func__ << ": New remote subscription replaced expired [" + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup.first << "]"; + continue; + } + + // Note: get_remote_subscription delivers a copied + // set of subscriptions. Thus, its is possible to + // to remove them within the loop. + auto its_ep_definition = _reliable ? + its_subscription->get_reliable() : + its_subscription->get_unreliable(); + + if (!its_ep_definition && expire_all) + its_ep_definition = (!_reliable) ? + its_subscription->get_reliable() : + its_subscription->get_unreliable(); + + if (its_ep_definition + && its_ep_definition->get_address() == _address + && (expire_all || + (its_ep_definition->get_remote_port() >= _range.first + && its_ep_definition->get_remote_port() <= _range.second))) { + + // TODO: Check whether subscriptions to different hosts are valid. + // IF yes, we probably need to simply reset the corresponding + // endpoint instead of removing the subscription... + VSOMEIP_INFO << __func__ + << ": removing subscription to " + << std::hex << its_info->get_service() << "." + << std::hex << its_info->get_instance() << "." + << std::hex << its_info->get_eventgroup() + << " from target " + << its_ep_definition->get_address() << ":" + << std::dec << its_ep_definition->get_port() + << " reliable=" + << std::boolalpha << its_ep_definition->is_reliable(); + if (expire_all) { + its_ep_definition = (!its_ep_definition->is_reliable()) ? + its_subscription->get_reliable() : + its_subscription->get_unreliable(); + if (its_ep_definition) { + VSOMEIP_INFO << __func__ + << ": removing subscription to " + << std::hex << its_info->get_service() << "." + << std::hex << its_info->get_instance() << "." + << std::hex << its_info->get_eventgroup() + << " from target " + << its_ep_definition->get_address() << ":" + << std::dec << its_ep_definition->get_port() + << " reliable=" + << std::boolalpha << its_ep_definition->is_reliable(); + } + } + its_subscription->set_expired(); + on_remote_unsubscribe(its_subscription); + } + } + } + } + } +} + +void routing_manager_impl::init_routing_info() { + VSOMEIP_INFO<< "Service Discovery disabled. Using static routing information."; + for (auto i : configuration_->get_remote_services()) { + boost::asio::ip::address its_address( + boost::asio::ip::address::from_string( + configuration_->get_unicast_address(i.first, i.second))); + uint16_t its_reliable_port + = configuration_->get_reliable_port(i.first, i.second); + uint16_t its_unreliable_port + = configuration_->get_unreliable_port(i.first, i.second); + + if (its_reliable_port != ILLEGAL_PORT + || its_unreliable_port != ILLEGAL_PORT) { + + add_routing_info(i.first, i.second, + DEFAULT_MAJOR, DEFAULT_MINOR, DEFAULT_TTL, + its_address, its_reliable_port, + its_address, its_unreliable_port); + + if(its_reliable_port != ILLEGAL_PORT) { + ep_mgr_impl_->find_or_create_remote_client( + i.first, i.second, true); + } + if(its_unreliable_port != ILLEGAL_PORT) { + ep_mgr_impl_->find_or_create_remote_client( + i.first, i.second, false); + } + } + } +} + +void routing_manager_impl::on_remote_subscribe( + std::shared_ptr<remote_subscription> &_subscription, + const remote_subscription_callback_t &_callback) { + + auto its_eventgroupinfo = _subscription->get_eventgroupinfo(); + if (!its_eventgroupinfo) { + VSOMEIP_ERROR << __func__ << " eventgroupinfo is invalid"; + return; + } + + const ttl_t its_ttl = _subscription->get_ttl(); + + const auto its_service = its_eventgroupinfo->get_service(); + const auto its_instance = its_eventgroupinfo->get_instance(); + const auto its_eventgroup = its_eventgroupinfo->get_eventgroup(); + const auto its_major = its_eventgroupinfo->get_major(); + + // Get remote port(s) + auto its_reliable = _subscription->get_reliable(); + if (its_reliable) { + uint16_t its_port + = configuration_->get_reliable_port(its_service, its_instance); + its_reliable->set_remote_port(its_port); + } + + auto its_unreliable = _subscription->get_unreliable(); + if (its_unreliable) { + uint16_t its_port + = configuration_->get_unreliable_port(its_service, its_instance); + its_unreliable->set_remote_port(its_port); + } + + // Calculate expiration time + const std::chrono::steady_clock::time_point its_expiration + = std::chrono::steady_clock::now() + std::chrono::seconds(its_ttl); + + // Try to update the subscription. This will fail, if the subscription does + // not exist or is still (partly) pending. + remote_subscription_id_t its_id; + std::set<client_t> its_added; + std::unique_lock<std::mutex> its_update_lock{update_remote_subscription_mutex_}; + if (_subscription->is_expired()) { + VSOMEIP_WARNING << __func__ << ": remote subscription already expired"; + return; + } else { + _subscription->set_forwarded(); + } + + auto its_result = its_eventgroupinfo->update_remote_subscription( + _subscription, its_expiration, its_added, its_id, true); + if (its_result) { + if (!_subscription->is_pending()) { // resubscription without change + its_update_lock.unlock(); + _callback(_subscription); + } else if (!its_added.empty()) { // new clients for a selective subscription + const client_t its_offering_client + = find_local_client(its_service, its_instance); + send_subscription(its_offering_client, + its_service, its_instance, its_eventgroup, its_major, + its_added, _subscription->get_id()); + } else { // identical subscription is not yet processed + std::stringstream its_warning; + its_warning << __func__ << " a remote subscription is already pending [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "]" + << " from "; + if (its_reliable && its_unreliable) + its_warning << "["; + if (its_reliable) + its_warning << its_reliable->get_address().to_string() + << ":" << std::dec << its_reliable->get_port(); + if (its_reliable && its_unreliable) + its_warning << ", "; + if (its_unreliable) + its_warning << its_unreliable->get_address().to_string() + << ":" << std::dec << its_unreliable->get_port(); + if (its_reliable && its_unreliable) + its_warning << "]"; + VSOMEIP_WARNING << its_warning.str(); + + its_update_lock.unlock(); + _callback(_subscription); + } + } else { // new subscription + if (its_eventgroupinfo->is_remote_subscription_limit_reached( + _subscription)) { + _subscription->set_all_client_states( + remote_subscription_state_e::SUBSCRIPTION_NACKED); + + its_update_lock.unlock(); + _callback(_subscription); + return; + } + + auto its_id + = its_eventgroupinfo->add_remote_subscription(_subscription); + + const client_t its_offering_client + = find_local_client(its_service, its_instance); + send_subscription(its_offering_client, + its_service, its_instance, its_eventgroup, its_major, + _subscription->get_clients(), its_id); + } +} + +void routing_manager_impl::on_remote_unsubscribe( + std::shared_ptr<remote_subscription> &_subscription) { + std::shared_ptr<eventgroupinfo> its_info + = _subscription->get_eventgroupinfo(); + if (!its_info) { + VSOMEIP_ERROR << __func__ + << ": Received Unsubscribe for unregistered eventgroup."; + return; + } + + const auto its_service = its_info->get_service(); + const auto its_instance = its_info->get_instance(); + const auto its_eventgroup = its_info->get_eventgroup(); + const auto its_major = its_info->get_major(); + + // Get remote port(s) + auto its_reliable = _subscription->get_reliable(); + if (its_reliable) { + uint16_t its_port + = configuration_->get_reliable_port(its_service, its_instance); + its_reliable->set_remote_port(its_port); + } + + auto its_unreliable = _subscription->get_unreliable(); + if (its_unreliable) { + uint16_t its_port + = configuration_->get_unreliable_port(its_service, its_instance); + its_unreliable->set_remote_port(its_port); + } + + remote_subscription_id_t its_id(0); + std::set<client_t> its_removed; + std::unique_lock<std::mutex> its_update_lock{update_remote_subscription_mutex_}; + auto its_result = its_info->update_remote_subscription( + _subscription, std::chrono::steady_clock::now(), + its_removed, its_id, false); + + if (its_result) { + const client_t its_offering_client + = find_local_client(its_service, its_instance); + send_unsubscription(its_offering_client, + its_service, its_instance, its_eventgroup, its_major, + its_removed, its_id); + } +} + +void routing_manager_impl::on_subscribe_ack_with_multicast( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port) { + ep_mgr_impl_->find_or_create_multicast_endpoint(_service, + _instance, _sender, _address, _port); +} + +void routing_manager_impl::on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _id) { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + auto its_subscription = its_eventgroup->get_remote_subscription(_id); + if (its_subscription) { + its_subscription->set_client_state(_client, + remote_subscription_state_e::SUBSCRIPTION_ACKED); + + auto its_parent = its_subscription->get_parent(); + if (its_parent) { + its_parent->set_client_state(_client, + remote_subscription_state_e::SUBSCRIPTION_ACKED); + if (!its_subscription->is_pending()) { + its_eventgroup->remove_remote_subscription(_id); + } + } + + if (discovery_) { + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + remote_subscribers_[_service][_instance][VSOMEIP_ROUTING_CLIENT].insert( + its_subscription->get_subscriber()); + discovery_->update_remote_subscription(its_subscription); + + VSOMEIP_INFO << "REMOTE SUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " from " << its_subscription->get_subscriber()->get_address() + << ":" << std::dec << its_subscription->get_subscriber()->get_port() + << (its_subscription->get_subscriber()->is_reliable() ? " reliable" : " unreliable") + << " was accepted"; + + return; + } + } else { + const auto its_tuple = std::make_tuple(_service, _instance, _eventgroup, _client); + const auto its_state = remote_subscription_state_.find(its_tuple); + if (its_state != remote_subscription_state_.end()) { + if (its_state->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + // Already notified! + return; + } + } + remote_subscription_state_[its_tuple] = subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED; + } + + std::set<client_t> subscribed_clients; + if (_client == VSOMEIP_ROUTING_CLIENT) { + for (const auto &its_event : its_eventgroup->get_events()) { + if (_event == ANY_EVENT || _event == its_event->get_event()) { + const auto &its_subscribers = its_event->get_subscribers(); + subscribed_clients.insert(its_subscribers.begin(), its_subscribers.end()); + } + } + } else { + subscribed_clients.insert(_client); + } + + for (const auto &its_subscriber : subscribed_clients) { + if (its_subscriber == get_client()) { + if (_event == ANY_EVENT) { + for (const auto &its_event : its_eventgroup->get_events()) { + host_->on_subscription_status(_service, _instance, + _eventgroup, its_event->get_event(), + 0x0 /*OK*/); + } + } else { + host_->on_subscription_status(_service, _instance, + _eventgroup, _event, 0x0 /*OK*/); + } + } else if (stub_) { + stub_->send_subscribe_ack(its_subscriber, _service, + _instance, _eventgroup, _event); + } + } + } +} + +std::shared_ptr<endpoint> routing_manager_impl::find_or_create_remote_client( + service_t _service, instance_t _instance, bool _reliable) { + return ep_mgr_impl_->find_or_create_remote_client(_service, + _instance, _reliable); +} + +void routing_manager_impl::on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + bool _remove, remote_subscription_id_t _id) { + + auto its_eventgroup = find_eventgroup(_service, _instance, _eventgroup); + if (its_eventgroup) { + auto its_subscription = its_eventgroup->get_remote_subscription(_id); + if (its_subscription) { + its_subscription->set_client_state(_client, + remote_subscription_state_e::SUBSCRIPTION_NACKED); + + auto its_parent = its_subscription->get_parent(); + if (its_parent) { + its_parent->set_client_state(_client, + remote_subscription_state_e::SUBSCRIPTION_NACKED); + if (!its_subscription->is_pending()) { + its_eventgroup->remove_remote_subscription(_id); + } + } + + if (discovery_) { + discovery_->update_remote_subscription(its_subscription); + VSOMEIP_INFO << "REMOTE SUBSCRIBE(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " from " << its_subscription->get_subscriber()->get_address() + << ":" << std::dec << its_subscription->get_subscriber()->get_port() + << (its_subscription->get_subscriber()->is_reliable() ? " reliable" : " unreliable") + << " was not accepted"; + } + if (_remove) + its_eventgroup->remove_remote_subscription(_id); + } + } +} + +return_code_e routing_manager_impl::check_error(const byte_t *_data, length_t _size, + instance_t _instance) { + + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + + if (_size >= VSOMEIP_PAYLOAD_POS) { + if (utility::is_request(_data[VSOMEIP_MESSAGE_TYPE_POS]) + || utility::is_request_no_return(_data[VSOMEIP_MESSAGE_TYPE_POS]) ) { + if (_data[VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) { + VSOMEIP_WARNING << "Received a message with unsupported protocol version for service 0x" + << std::hex << its_service; + return return_code_e::E_WRONG_PROTOCOL_VERSION; + } + if (_instance == 0xFFFF) { + VSOMEIP_WARNING << "Receiving endpoint is not configured for service 0x" + << std::hex << its_service; + return return_code_e::E_UNKNOWN_SERVICE; + } + // Check interface version of service/instance + auto its_info = find_service(its_service, _instance); + if (its_info) { + major_version_t its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; + if (its_version != its_info->get_major()) { + VSOMEIP_WARNING << "Received a message with unsupported interface version for service 0x" + << std::hex << its_service; + return return_code_e::E_WRONG_INTERFACE_VERSION; + } + } + if (_data[VSOMEIP_RETURN_CODE_POS] != static_cast<byte_t> (return_code_e::E_OK)) { + // Request calls must to have return code E_OK set! + VSOMEIP_WARNING << "Received a message with unsupported return code set for service 0x" + << std::hex << its_service; + return return_code_e::E_NOT_OK; + } + } + } else { + // Message shorter than vSomeIP message header + VSOMEIP_WARNING << "Received a message message which is shorter than vSomeIP message header!"; + return return_code_e::E_MALFORMED_MESSAGE; + } + return return_code_e::E_OK; +} + +void routing_manager_impl::send_error(return_code_e _return_code, + const byte_t *_data, length_t _size, + instance_t _instance, bool _reliable, + endpoint* const _receiver, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + + client_t its_client = 0; + service_t its_service = 0; + method_t its_method = 0; + session_t its_session = 0; + major_version_t its_version = 0; + + if (_size >= VSOMEIP_CLIENT_POS_MAX) + its_client = bithelper::read_uint16_be(&_data[VSOMEIP_CLIENT_POS_MIN]); + if (_size >= VSOMEIP_SERVICE_POS_MAX) + its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + if (_size >= VSOMEIP_METHOD_POS_MAX) + its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + if (_size >= VSOMEIP_SESSION_POS_MAX) + its_session = bithelper::read_uint16_be(&_data[VSOMEIP_SESSION_POS_MIN]); + if( _size >= VSOMEIP_INTERFACE_VERSION_POS) + its_version = _data[VSOMEIP_INTERFACE_VERSION_POS]; + + auto error_message = runtime::get()->create_message(_reliable); + error_message->set_client(its_client); + error_message->set_instance(_instance); + error_message->set_interface_version(its_version); + error_message->set_message_type(message_type_e::MT_ERROR); + error_message->set_method(its_method); + error_message->set_return_code(_return_code); + error_message->set_service(its_service); + error_message->set_session(its_session); + { + std::shared_ptr<serializer> its_serializer(get_serializer()); + if (its_serializer->serialize(error_message.get())) { + if (_receiver) { + auto its_endpoint_def = std::make_shared<endpoint_definition>( + _remote_address, _remote_port, + _receiver->is_reliable()); + its_endpoint_def->set_remote_port(_receiver->get_local_port()); + std::shared_ptr<endpoint> its_endpoint = + ep_mgr_impl_->find_server_endpoint( + its_endpoint_def->get_remote_port(), + its_endpoint_def->is_reliable()); + if (its_endpoint) { + #ifdef USE_DLT + trace::header its_header; + if (its_header.prepare(its_endpoint, true, _instance)) + tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE, + _data, _size); + #else + (void) _instance; + #endif + its_endpoint->send_error(its_endpoint_def, + its_serializer->get_data(), its_serializer->get_size()); + } + } + its_serializer->reset(); + put_serializer(its_serializer); + } else { + VSOMEIP_ERROR<< "Failed to serialize error message."; + } + } +} + +void routing_manager_impl::clear_remote_subscriber( + service_t _service, instance_t _instance, client_t _client, + const std::shared_ptr<endpoint_definition> &_target) { + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + auto its_service = remote_subscribers_.find(_service); + if (its_service != remote_subscribers_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_client = its_instance->second.find(_client); + if (its_client != its_instance->second.end()) { + if (its_client->second.erase(_target)) { + if (!its_client->second.size()) { + its_instance->second.erase(_client); + } + } + } + } + } +} + +std::chrono::steady_clock::time_point +routing_manager_impl::expire_subscriptions(bool _force) { + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<eventgroupinfo> > > >its_eventgroups; + std::map<std::shared_ptr<remote_subscription>, + std::set<client_t> > its_expired_subscriptions; + + std::chrono::steady_clock::time_point now + = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point its_next_expiration + = std::chrono::steady_clock::now() + std::chrono::hours(24); + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + its_eventgroups = eventgroups_; + } + + for (auto &its_service : its_eventgroups) { + for (auto &its_instance : its_service.second) { + for (auto &its_eventgroup : its_instance.second) { + auto its_subscriptions + = its_eventgroup.second->get_remote_subscriptions(); + for (auto &s : its_subscriptions) { + if(!s) { + VSOMEIP_ERROR << __func__ + << ": Remote subscription is NULL for eventgroup [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service.first << "." + << std::setw(4) << its_instance.first << "." + << std::setw(4) << its_eventgroup.first << "]"; + continue; + } else if (s->is_forwarded()) { + VSOMEIP_WARNING << __func__ << ": New remote subscription replaced expired [" + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_eventgroup.first << "]"; + continue; + } + for (auto its_client : s->get_clients()) { + if (_force) { + its_expired_subscriptions[s].insert(its_client); + } else { + auto its_expiration = s->get_expiration(its_client); + if (its_expiration != std::chrono::steady_clock::time_point()) { + if (its_expiration < now) { + its_expired_subscriptions[s].insert(its_client); + } else if (its_expiration < its_next_expiration) { + its_next_expiration = its_expiration; + } + } + } + } + } + } + } + } + + for (auto &s : its_expired_subscriptions) { + s.first->set_expired(); + auto its_info = s.first->get_eventgroupinfo(); + if (its_info) { + auto its_service = its_info->get_service(); + auto its_instance = its_info->get_instance(); + auto its_eventgroup = its_info->get_eventgroup(); + + remote_subscription_id_t its_id; + std::unique_lock<std::mutex> its_update_lock{update_remote_subscription_mutex_}; + auto its_result = its_info->update_remote_subscription( + s.first, std::chrono::steady_clock::now(), + s.second, its_id, false); + if (its_result) { + const client_t its_offering_client + = find_local_client(its_service, its_instance); + const auto its_subscription = its_info->get_remote_subscription(its_id); + if (its_subscription) { + its_info->remove_remote_subscription(its_id); + + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + remote_subscribers_[its_service][its_instance].erase(its_offering_client); + + if (its_info->get_remote_subscriptions().size() == 0) { + for (const auto &its_event : its_info->get_events()) { + bool has_remote_subscriber(false); + for (const auto &its_eventgroup : its_event->get_eventgroups()) { + const auto its_eventgroup_info + = find_eventgroup(its_service, its_instance, its_eventgroup); + if (its_eventgroup_info + && its_eventgroup_info->get_remote_subscriptions().size() > 0) { + has_remote_subscriber = true; + } + } + if (!has_remote_subscriber && its_event->is_shadow()) { + its_event->unset_payload(); + } + } + } + } else { + VSOMEIP_ERROR << __func__ + << ": Unknown expired subscription " << std::dec << its_id << " for eventgroup [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "]"; + } + send_expired_subscription(its_offering_client, + its_service, its_instance, its_eventgroup, + s.second, s.first->get_id()); + } + + if (s.first->get_unreliable()) { + VSOMEIP_INFO << (_force ? "Removed" : "Expired") << " subscription [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "] unreliable from " + << s.first->get_unreliable()->get_address() << ":" + << std::dec << s.first->get_unreliable()->get_port(); + } + + if (s.first->get_reliable()) { + VSOMEIP_INFO << (_force ? "Removed" : "Expired") << " subscription [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "] reliable from " + << s.first->get_reliable()->get_address() << ":" + << std::dec << s.first->get_reliable()->get_port(); + } + } + } + + return its_next_expiration; +} + +void routing_manager_impl::log_version_timer_cbk(boost::system::error_code const & _error) { + if (!_error) { + static int its_counter(0); + static uint32_t its_interval = configuration_->get_log_version_interval(); + + bool is_diag_mode(false); + + if (discovery_) { + is_diag_mode = discovery_->get_diagnosis_mode(); + } + std::stringstream its_last_resume; + { + std::lock_guard<std::mutex> its_lock(routing_state_mutex_); + if (last_resume_ != std::chrono::steady_clock::time_point::min()) { + its_last_resume << " | " << std::dec + << std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::steady_clock::now() - last_resume_).count() << "s"; + } + } + + VSOMEIP_INFO << "vSomeIP " << VSOMEIP_VERSION << " | (" + << ((is_diag_mode == true) ? "diagnosis)" : "default)") + << its_last_resume.str(); + + its_counter++; + if (its_counter == 6) { + ep_mgr_->log_client_states(); + ep_mgr_impl_->log_client_states(); + its_counter = 0; + } + + { + std::lock_guard<std::mutex> its_lock(version_log_timer_mutex_); + version_log_timer_.expires_from_now(std::chrono::seconds(its_interval)); + version_log_timer_.async_wait( + std::bind(&routing_manager_impl::log_version_timer_cbk, + this, std::placeholders::_1)); + } + } +} + +bool routing_manager_impl::handle_local_offer_service(client_t _client, service_t _service, + instance_t _instance, major_version_t _major,minor_version_t _minor) { + { + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + auto found_service = local_services_.find(_service); + if (found_service != local_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + const major_version_t its_stored_major(std::get<0>(found_instance->second)); + const minor_version_t its_stored_minor(std::get<1>(found_instance->second)); + const client_t its_stored_client(std::get<2>(found_instance->second)); + if ( its_stored_major == _major + && its_stored_minor == _minor + && its_stored_client == _client) { + VSOMEIP_WARNING << "routing_manager_impl::handle_local_offer_service: " + << "Application: " + << std::hex << std::setfill('0') + << std::setw(4) << _client << " is offering: [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec << static_cast<std::uint32_t>(_major) << "." + << _minor << "] offered previously by itself."; + return false; + } else if ( its_stored_major == _major + && its_stored_minor == _minor + && its_stored_client != _client) { + // check if previous offering application is still alive + bool already_pinged(false); + { + std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); + auto found_service2 = pending_offers_.find(_service); + if (found_service2 != pending_offers_.end()) { + auto found_instance2 = found_service2->second.find(_instance); + if (found_instance2 != found_service2->second.end()) { + if(std::get<2>(found_instance2->second) == _client) { + already_pinged = true; + } else { + VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: " + << "rejecting service registration. Application: " + << std::hex << std::setfill('0') + << std::setw(4) << _client << " is trying to offer [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(_major) << "." << _minor + << "] current pending offer by application: " << std::hex + << std::setw(4) << its_stored_client << ": [" + << std::hex + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(its_stored_major) + << "." << its_stored_minor << "]"; + return false; + } + } + } + } + if (!already_pinged) { + // find out endpoint of previously offering application + auto its_old_endpoint = find_local(its_stored_client); + if (its_old_endpoint) { + std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); + if (stub_ && stub_->send_ping(its_stored_client)) { + pending_offers_[_service][_instance] = + std::make_tuple(_major, _minor, _client, + its_stored_client); + VSOMEIP_WARNING << "OFFER(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << ":" + << std::dec << int(_major) << "." << std::dec << _minor + << "] is now pending. Waiting for pong from application: " + << std::hex << std::setw(4) << its_stored_client; + return false; + } + } else if (its_stored_client == host_->get_client()) { + VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: " + << "rejecting service registration. Application: " + << std::hex << std::setfill('0') + << std::setw(4) << _client << " is trying to offer [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(_major) << "." << _minor + << "] offered previously by routing manager stub itself with application: " + << std::hex + << std::setw(4) << its_stored_client << ": [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(its_stored_major) << "." << its_stored_minor + << "] which is still alive"; + return false; + } + } else { + VSOMEIP_INFO << __func__ + << std::hex << std::setw(4) << std::setfill('0') << _client <<"): [" + << std::hex << std::setw(4) << std::setfill('0') << _service << "." + << std::hex << std::setw(4) << std::setfill('0') << _instance + << ":" << std::dec << int(_major) << "." << std::dec << _minor << "]" + << " client already pinged!"; + return false; + } + } else { + VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: " + << "rejecting service registration. Application: " + << std::hex << std::setfill('0') + << std::setw(4) << _client << " is trying to offer [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(_major) << "." << _minor + << "] offered previously by application: " + << std::hex + << std::setw(4) << its_stored_client << ": [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(its_stored_major) << "." << its_stored_minor << "]"; + return false; + } + } + } + + // check if the same service instance is already offered remotely + if (routing_manager_base::offer_service(_client, _service, _instance, + _major, _minor)) { + local_services_[_service][_instance] = std::make_tuple(_major, + _minor, _client); + } else { + VSOMEIP_ERROR << "routing_manager_impl::handle_local_offer_service: " + << "rejecting service registration. Application: " + << std::hex << std::setfill('0') + << std::setw(4) << _client << " is trying to offer [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::dec + << static_cast<std::uint32_t>(_major) << "." << _minor << "]" + << "] already offered remotely"; + return false; + } + } + return true; +} + +void routing_manager_impl::on_pong(client_t _client) { + std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); + if (pending_offers_.size() == 0) { + return; + } + for (auto service_iter = pending_offers_.begin(); + service_iter != pending_offers_.end(); ) { + for (auto instance_iter = service_iter->second.begin(); + instance_iter != service_iter->second.end(); ) { + if (std::get<3>(instance_iter->second) == _client) { + // received pong from an application were another application wants + // to offer its service, delete the other applications offer as + // the current offering application is still alive + VSOMEIP_WARNING << "OFFER(" + << std::hex << std::setfill('0') + << std::setw(4) << std::get<2>(instance_iter->second) << "): [" + << std::setw(4) << service_iter->first << "." + << std::setw(4) << instance_iter->first << ":" + << std::dec + << std::uint32_t(std::get<0>(instance_iter->second)) + << "." << std::get<1>(instance_iter->second) + << "] was rejected as application: " + << std::hex + << std::setw(4) << _client + << " is still alive"; + instance_iter = service_iter->second.erase(instance_iter); + } else { + ++instance_iter; + } + } + + if (service_iter->second.size() == 0) { + service_iter = pending_offers_.erase(service_iter); + } else { + ++service_iter; + } + } +} + +void routing_manager_impl::register_client_error_handler(client_t _client, + const std::shared_ptr<endpoint> &_endpoint) { + _endpoint->register_error_handler( + std::bind(&routing_manager_impl::handle_client_error, this, _client)); +} + +void routing_manager_impl::handle_client_error(client_t _client) { + VSOMEIP_INFO << "rmi::" << __func__ << " Client 0x" << std::hex << get_client() + << " handles a client error(" << std::hex << _client << ")"; + if (stub_) + stub_->update_registration(_client, registration_type_e::DEREGISTER_ON_ERROR, + boost::asio::ip::address(), 0); + + std::forward_list<std::tuple<client_t, service_t, instance_t, major_version_t, + minor_version_t>> its_offers; + { + std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); + if (pending_offers_.size() == 0) { + return; + } + + for (auto service_iter = pending_offers_.begin(); + service_iter != pending_offers_.end(); ) { + for (auto instance_iter = service_iter->second.begin(); + instance_iter != service_iter->second.end(); ) { + if (std::get<3>(instance_iter->second) == _client) { + VSOMEIP_WARNING << "OFFER(" + << std::hex << std::setfill('0') + << std::setw(4) << std::get<2>(instance_iter->second) << "): [" + << std::setw(4) << service_iter->first << "." + << std::setw(4) << instance_iter->first << ":" + << std::dec + << std::uint32_t(std::get<0>(instance_iter->second)) + << "." << std::get<1>(instance_iter->second) + << "] is not pending anymore as application: " + << std::hex + << std::setw(4) << std::get<3>(instance_iter->second) + << " is dead. Offering again!"; + its_offers.push_front(std::make_tuple( + std::get<2>(instance_iter->second), + service_iter->first, + instance_iter->first, + std::get<0>(instance_iter->second), + std::get<1>(instance_iter->second))); + instance_iter = service_iter->second.erase(instance_iter); + } else { + ++instance_iter; + } + } + + if (service_iter->second.size() == 0) { + service_iter = pending_offers_.erase(service_iter); + } else { + ++service_iter; + } + } + } + for (const auto &offer : its_offers) { + offer_service(std::get<0>(offer), std::get<1>(offer), std::get<2>(offer), + std::get<3>(offer), std::get<4>(offer), true); + } +} + +std::shared_ptr<endpoint_manager_impl> routing_manager_impl::get_endpoint_manager() const { + return ep_mgr_impl_; +} + +void routing_manager_impl::send_subscribe(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter) { + auto endpoint = ep_mgr_->find_local(_service, _instance); + if (endpoint && stub_) { + stub_->send_subscribe(endpoint, _client, + _service, _instance, + _eventgroup, _major, + _event, _filter, + PENDING_SUBSCRIPTION_ID); + } +} + +routing_state_e routing_manager_impl::get_routing_state() { + return routing_manager_base::get_routing_state(); +} + +void routing_manager_impl::set_routing_state(routing_state_e _routing_state) { + { + std::lock_guard<std::mutex> its_lock(routing_state_mutex_); + if (routing_state_ == _routing_state) { + VSOMEIP_INFO << "rmi::" << __func__ << " No routing state change --> do nothing."; + return; + } + + routing_state_ = _routing_state; + } + + if (discovery_) { + switch (_routing_state) { + case routing_state_e::RS_SUSPENDED: + { + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to suspend mode, diagnosis mode is " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + + // stop processing of incoming SD messages + discovery_->stop(); + + // stop all endpoints + ep_mgr_->suspend(); + + VSOMEIP_INFO << "rmi::" << __func__ << " Inform all applications that we are going to suspend"; + send_suspend(); + + // remove all remote subscriptions to remotely offered services on this node + expire_subscriptions(true); + + std::vector<std::shared_ptr<serviceinfo>> _service_infos; + // send StopOffer messages for remotely offered services on this node + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + bool has_reliable(its_instance.second->get_endpoint(true) != nullptr); + bool has_unreliable(its_instance.second->get_endpoint(false) != nullptr); + if (has_reliable || has_unreliable) { + const client_t its_client(find_local_client(its_service.first, its_instance.first)); + if (its_client == VSOMEIP_ROUTING_CLIENT) { + // Inconsistency between services_ and local_services_ table detected + // --> cleanup. + VSOMEIP_WARNING << "rmi::" << __func__ << " Found table inconsistency for [" + << std::hex << std::setw(4) << std::setfill('0') << its_service.first << "." + << std::hex << std::setw(4) << std::setfill('0') << its_instance.first << "]"; + + // Remove the service from the offer_commands_ and prepare_stop_handlers_ to force the next offer to be processed + offer_commands_.erase(std::make_pair(its_service.first, its_instance.first)); + if (has_reliable) + its_instance.second->get_endpoint(true)->remove_stop_handler(its_service.first); + if (has_unreliable) + its_instance.second->get_endpoint(false)->remove_stop_handler(its_service.first); + + del_routing_info(its_service.first, its_instance.first, has_reliable, has_unreliable); + + std::lock_guard<std::mutex> its_lock(pending_offers_mutex_); + auto its_pending_offer = pending_offers_.find(its_service.first); + if (its_pending_offer != pending_offers_.end()) + its_pending_offer->second.erase(its_instance.first); + + } + VSOMEIP_WARNING << "Service " + << std::hex << std::setfill('0') + << std::setw(4) << its_service.first << "." + << std::setw(4) << its_instance.first << " still offered by " + << std::setw(4) << its_client; + } + // collect stop offers to be sent out + if (discovery_->stop_offer_service(its_instance.second, false)) { + _service_infos.push_back(its_instance.second); + } + } + } + // send collected stop offers packed together in one ore multiple SD messages + discovery_->send_collected_stop_offers(_service_infos); + _service_infos.clear(); + + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + remote_subscription_state_.clear(); + } + + // Remove all subscribers to shadow events + clear_shadow_subscriptions(); + + // send StopSubscribes and clear subscribed_ map + discovery_->unsubscribe_all_on_suspend(); + + // mark all external services as offline + services_t its_remote_services; + { + std::lock_guard<std::mutex> its_lock(services_remote_mutex_); + its_remote_services = services_remote_; + } + for (const auto &s : its_remote_services) { + for (const auto &i : s.second) { + const bool has_reliable(i.second->get_endpoint(true)); + const bool has_unreliable(i.second->get_endpoint(false)); + del_routing_info(s.first, i.first, has_reliable, has_unreliable); + + // clear all cached payloads of remote services + unset_all_eventpayloads(s.first, i.first); + } + } + + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to suspend mode done, diagnosis mode is " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + + break; + } + case routing_state_e::RS_RESUMED: + { + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to resume mode, diagnosis mode was " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + { + std::lock_guard<std::mutex> its_lock(routing_state_mutex_); + last_resume_ = std::chrono::steady_clock::now(); + } + + // Reset relevant in service info + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + its_instance.second->set_ttl(DEFAULT_TTL); + its_instance.second->set_is_in_mainphase(false); + } + } + // Switch SD back to normal operation + discovery_->set_diagnosis_mode(false); + + if (routing_state_handler_) { + routing_state_handler_(_routing_state); + } + + // start all endpoints + ep_mgr_->resume(); + + // start processing of SD messages (incoming remote offers should lead to new subscribe messages) + discovery_->start(); + + // Trigger initial offer phase for relevant services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + discovery_->offer_service(its_instance.second); + } + } + + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to resume mode done, diagnosis mode was " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + break; + } + case routing_state_e::RS_DIAGNOSIS: + { + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to diagnosis mode."; + discovery_->set_diagnosis_mode(true); + + // send StopOffer messages for all someip protocol services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + discovery_->stop_offer_service(its_instance.second, true); + } + } + } + + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to diagnosis mode done."; + break; + } + case routing_state_e::RS_RUNNING: + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to running mode, diagnosis mode was " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + + // Reset relevant in service info + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + its_instance.second->set_ttl(DEFAULT_TTL); + its_instance.second->set_is_in_mainphase(false); + } + } + } + // Switch SD back to normal operation + discovery_->set_diagnosis_mode(false); + + // Trigger initial phase for relevant services + for (const auto &its_service : get_offered_services()) { + for (const auto &its_instance : its_service.second) { + if (host_->get_configuration()->is_someip( + its_service.first, its_instance.first)) { + discovery_->offer_service(its_instance.second); + } + } + } + + VSOMEIP_INFO << "rmi::" << __func__ << " Set routing to running mode done, diagnosis mode was " + << ((discovery_->get_diagnosis_mode() == true) ? "active." : "inactive."); + break; + default: + break; + } + } +} + +void routing_manager_impl::on_net_interface_or_route_state_changed( + bool _is_interface, const std::string &_if, bool _available) { + std::lock_guard<std::mutex> its_lock(pending_sd_offers_mutex_); + auto log_change_message = [&_if, _available, _is_interface](bool _warning) { + std::stringstream ss; + ss << (_is_interface ? "Network interface" : "Route") << " \"" << _if + << "\" state changed: " << (_available ? "up" : "down"); + if (_warning) { + VSOMEIP_WARNING << ss.str(); + } else { + VSOMEIP_INFO << ss.str(); + } + }; + if (_is_interface) { + if (if_state_running_ + || (_available && !if_state_running_ && routing_running_)) { + log_change_message(true); + } else if (!if_state_running_) { + log_change_message(false); + } + if (_available && !if_state_running_) { + if_state_running_ = true; + if (!routing_running_) { + if(configuration_->is_sd_enabled()) { + if (sd_route_set_) { + start_ip_routing(); + } + } else { + // Static routing, don't wait for route! + start_ip_routing(); + } + } + } + } else { + if (sd_route_set_ + || (_available && !sd_route_set_ && routing_running_)) { + log_change_message(true); + } else if (!sd_route_set_) { + log_change_message(false); + } + if (_available && !sd_route_set_) { + sd_route_set_ = true; + if (!routing_running_) { + if (if_state_running_) { + start_ip_routing(); + } + } + } + } +} + +void routing_manager_impl::start_ip_routing() { +#if defined(_WIN32) || defined(__QNX__) + if_state_running_ = true; +#endif + + if (routing_ready_handler_) { + routing_ready_handler_(); + } + if (discovery_) { + discovery_->start(); + } else { + init_routing_info(); + } + + for (auto its_service : pending_sd_offers_) { + init_service_info(its_service.first, its_service.second, true); + } + pending_sd_offers_.clear(); + + routing_running_ = true; + VSOMEIP_INFO << VSOMEIP_ROUTING_READY_MESSAGE; +} + +void +routing_manager_impl::add_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + requested_services_[_service][_instance][_major][_minor].insert(_client); +} + +void +routing_manager_impl::remove_requested_service(client_t _client, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + + using minor_map_t = std::map<minor_version_t, std::set<client_t> >; + using major_map_t = std::map<major_version_t, minor_map_t>; + using instance_map_t = std::map<instance_t, major_map_t>; + + auto delete_client = [&_client]( + minor_map_t::iterator& _minor_iter, + const major_map_t::iterator& _parent_major_iter) { + if (_minor_iter->second.erase(_client)) { // client was requester + if (_minor_iter->second.empty()) { + // client was last requester of this minor version + _minor_iter = _parent_major_iter->second.erase(_minor_iter); + } else { // there are still other requesters of this minor version + ++_minor_iter; + } + } else { // client wasn't requester + ++_minor_iter; + } + }; + + auto handle_minor = [&_minor, &delete_client]( + major_map_t::iterator& _major_iter, + const instance_map_t::iterator& _parent_instance_iter) { + if (_minor == ANY_MINOR) { + for (auto minor_iter = _major_iter->second.begin(); + minor_iter != _major_iter->second.end(); ) { + delete_client(minor_iter, _major_iter); + } + } else { + auto found_minor = _major_iter->second.find(_minor); + if (found_minor != _major_iter->second.end()) { + delete_client(found_minor, _major_iter); + } + } + if (_major_iter->second.empty()) { + // client was last requester of this major version + _major_iter = _parent_instance_iter->second.erase(_major_iter); + } else { + ++_major_iter; + } + }; + + auto found_service = requested_services_.find(_service); + if (found_service != requested_services_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (_major == ANY_MAJOR) { + for (auto major_iter = found_instance->second.begin(); + major_iter != found_instance->second.end();) { + handle_minor(major_iter, found_instance); + } + } else { + auto found_major = found_instance->second.find(_major); + if (found_major != found_instance->second.end()) { + handle_minor(found_major, found_instance); + } + } + if (found_instance->second.empty()) { + // client was last requester of this instance + found_service->second.erase(found_instance); + if (found_service->second.empty()) { + // client was last requester of this service + requested_services_.erase(found_service); + } + } + } + } +} + +std::vector<std::pair<service_t, instance_t> > +routing_manager_impl::get_requested_services(client_t _client) { + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + std::vector<std::pair<service_t, instance_t>> its_requests; + for (const auto& service : requested_services_) { + for (const auto& instance : service.second) { + bool requested = false; + for (const auto& major : instance.second) { + for (const auto& minor : major.second) { + if (minor.second.find(_client) != minor.second.end()) { + requested = true; + break; + } + } + if (requested) { + break; + } + } + if (requested) { + its_requests.push_back( + std::make_pair(service.first, instance.first)); + break; + } + } + } + return its_requests; +} + +std::set<client_t> +routing_manager_impl::get_requesters(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> ist_lock(requested_services_mutex_); + return get_requesters_unlocked(_service, _instance, _major, _minor); +} + +std::set<client_t> +routing_manager_impl::get_requesters_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::set<client_t> its_requesters; + + auto found_service = requested_services_.find(_service); + if (found_service == requested_services_.end()) { + found_service = requested_services_.find(ANY_SERVICE); + if (found_service == requested_services_.end()) { + return its_requesters; + } + } + + auto found_instance = found_service->second.find(_instance); + if (found_instance == found_service->second.end()) { + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance == found_service->second.end()) { + return its_requesters; + } + } + + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + if (its_requesters.empty()) { + its_requesters = its_minor.second; + } else { + its_requesters.insert(its_minor.second.cbegin(), + its_minor.second.cend()); + } + } + } + } + } + + return its_requesters; +} + +bool +routing_manager_impl::has_requester_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + auto found_service = requested_services_.find(_service); + if (found_service == requested_services_.end()) { + found_service = requested_services_.find(ANY_SERVICE); + if (found_service == requested_services_.end()) { + return false; + } + } + + auto found_instance = found_service->second.find(_instance); + if (found_instance == found_service->second.end()) { + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance == found_service->second.end()) { + return false; + } + } + + for (const auto& its_major : found_instance->second) { + if (its_major.first == _major || _major == DEFAULT_MAJOR + || its_major.first == ANY_MAJOR) { + for (const auto &its_minor : its_major.second) { + if (its_minor.first <= _minor + || _minor == DEFAULT_MINOR + || its_minor.first == ANY_MINOR) { + + return true; + } + } + } + } + + return false; +} + +std::set<eventgroup_t> +routing_manager_impl::get_subscribed_eventgroups( + service_t _service, instance_t _instance) { + std::set<eventgroup_t> its_eventgroups; + + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto& its_group : found_instance->second) { + for (const auto& its_event : its_group.second->get_events()) { + if (its_event->has_subscriber(its_group.first, ANY_CLIENT)) { + its_eventgroups.insert(its_group.first); + } + } + } + } + } + + return its_eventgroups; +} + +void routing_manager_impl::clear_targets_and_pending_sub_from_eventgroups( + service_t _service, instance_t _instance) { + std::vector<std::shared_ptr<event>> its_events; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + auto found_service = eventgroups_.find(_service); + if (found_service != eventgroups_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (const auto &its_eventgroup : found_instance->second) { + // As the service is gone, all subscriptions to its events + // do no longer exist and the last received payload is no + // longer valid. + for (auto &its_event : its_eventgroup.second->get_events()) { + const auto its_subscribers = its_event->get_subscribers(); + for (const auto its_subscriber : its_subscribers) { + if (its_subscriber != get_client()) { + its_event->remove_subscriber( + its_eventgroup.first, its_subscriber); + } + + client_t its_client = VSOMEIP_ROUTING_CLIENT; //is_specific_endpoint_client(its_subscriber, _service, _instance); + { + std::lock_guard<std::mutex> its_lock(remote_subscription_state_mutex_); + const auto its_tuple = + std::make_tuple(found_service->first, found_instance->first, + its_eventgroup.first, its_client); + remote_subscription_state_.erase(its_tuple); + } + } + its_events.push_back(its_event); + } + // TODO dn: find out why this was commented out + //its_eventgroup.second->clear_targets(); + //its_eventgroup.second->clear_pending_subscriptions(); + } + } + } + } + for (const auto& e : its_events) { + e->unset_payload(true); + } +} + +void routing_manager_impl::clear_remote_subscriber(service_t _service, + instance_t _instance) { + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + auto found_service = remote_subscribers_.find(_service); + if (found_service != remote_subscribers_.end()) { + if (found_service->second.erase(_instance) > 0 && + !found_service->second.size()) { + remote_subscribers_.erase(found_service); + } + } +} + + +void routing_manager_impl::call_sd_endpoint_connected( + const boost::system::error_code& _error, + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint>& _endpoint, + std::shared_ptr<boost::asio::steady_timer> _timer) { + (void)_timer; + if (_error) { + return; + } + _endpoint->set_established(true); + if (discovery_) { + discovery_->on_endpoint_connected(_service, _instance, + _endpoint); + } +} + +bool routing_manager_impl::create_placeholder_event_and_subscribe( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + client_t _client) { + + bool is_inserted(false); + // we received a event which was not yet requested/offered + // create a placeholder field until someone requests/offers this event with + // full information like eventgroup, field or not etc. + std::set<eventgroup_t> its_eventgroups({_eventgroup}); + + const client_t its_local_client(find_local_client(_service, _instance)); + if (its_local_client == host_->get_client()) { + // received subscription for event of a service instance hosted by + // application acting as rm_impl register with own client id and shadow = false + register_event(host_->get_client(), + _service, _instance, + _event, + its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, + nullptr, false, false, true); + } else if (its_local_client != VSOMEIP_ROUTING_CLIENT) { + // received subscription for event of a service instance hosted on + // this node register with client id of local_client and set shadow to true + register_event(its_local_client, + _service, _instance, + _event, its_eventgroups, event_type_e::ET_UNKNOWN, + reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), false, true, + nullptr, false, true, true); + } else { + // received subscription for event of a unknown or remote service instance + std::shared_ptr<serviceinfo> its_info = find_service(_service, + _instance); + if (its_info && !its_info->is_local()) { + // remote service, register shadow event with client ID of subscriber + // which should have called register_event + register_event(_client, + _service, _instance, + _event, its_eventgroups, event_type_e::ET_UNKNOWN, + reliability_type_e::RT_UNKNOWN, + std::chrono::milliseconds::zero(), + false, true, nullptr, false, true, true); + } else { + VSOMEIP_WARNING + << "routing_manager_impl::create_placeholder_event_and_subscribe(" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " received subscription for unknown service instance."; + } + } + + std::shared_ptr<event> its_event = find_event(_service, _instance, _event); + if (its_event) { + is_inserted = its_event->add_subscriber( + _eventgroup, _filter, _client, false); + } + return is_inserted; +} + +void routing_manager_impl::handle_subscription_state( + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { +#if 0 + VSOMEIP_ERROR << "routing_manager_impl::" << __func__ + << "(" << std::hex << _client << "): " + << "event=" + << std::hex << _service << "." + << std::hex << _instance << "." + << std::hex << _eventgroup << "." + << std::hex << _event + << " me=" + << std::hex << get_client(); +#endif + // Note: remote_subscription_state_mutex_ is already locked as this + // method builds a critical section together with insert_subscription + // from routing_manager_base. + // Todo: Improve this situation... + auto its_event = find_event(_service, _instance, _event); + client_t its_client(VSOMEIP_ROUTING_CLIENT); + if (its_event && + its_event->get_type() == event_type_e::ET_SELECTIVE_EVENT) { + its_client = _client; + } + + auto its_tuple + = std::make_tuple(_service, _instance, _eventgroup, its_client); + auto its_state = remote_subscription_state_.find(its_tuple); + if (its_state != remote_subscription_state_.end()) { +#if 0 + VSOMEIP_ERROR << "routing_manager_impl::" << __func__ + << "(" << std::hex << _client << "): " + << "event=" + << std::hex << _service << "." + << std::hex << _instance << "." + << std::hex << _eventgroup << "." + << std::hex << _event + << " state=" << std::hex << (int)its_state->second + << " me=" + << std::hex << get_client(); +#endif + if (its_state->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + // Subscription already acknowledged! + if (_client == get_client()) { + host_->on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /*OK*/); + } else if (stub_) { + stub_->send_subscribe_ack(_client, _service, _instance, _eventgroup, _event); + } + } + } +} + +void routing_manager_impl::register_sd_acceptance_handler( + const sd_acceptance_handler_t& _handler) const { + if (discovery_) { + discovery_->register_sd_acceptance_handler(_handler); + } +} + +void routing_manager_impl::register_reboot_notification_handler( + const reboot_notification_handler_t& _handler) const { + if (discovery_) { + discovery_->register_reboot_notification_handler(_handler); + } +} + +void routing_manager_impl::register_routing_ready_handler( + const routing_ready_handler_t& _handler) { + routing_ready_handler_ = _handler; +} + +void routing_manager_impl::register_routing_state_handler( + const routing_state_handler_t& _handler) { + routing_state_handler_ = _handler; +} + +void routing_manager_impl::sd_acceptance_enabled( + const boost::asio::ip::address& _address, + const configuration::port_range_t& _range, bool _reliable) { + expire_subscriptions(_address, _range, _reliable); + expire_services(_address, _range, _reliable); +} + +void routing_manager_impl::memory_log_timer_cbk( + boost::system::error_code const & _error) { + if (_error) { + return; + } + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + static const std::uint32_t its_pagesize = static_cast<std::uint32_t>(getpagesize() / 1024); + + std::FILE *its_file = std::fopen("/proc/self/statm", "r"); + if (!its_file) { + VSOMEIP_ERROR << "memory_log_timer_cbk: couldn't open:" + << std::string(std::strerror(errno)); + return; + } + std::uint64_t its_size(0); + std::uint64_t its_rsssize(0); + std::uint64_t its_sharedpages(0); + std::uint64_t its_text(0); + std::uint64_t its_lib(0); + std::uint64_t its_data(0); + std::uint64_t its_dirtypages(0); + + if (EOF == std::fscanf(its_file, "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64, &its_size, + &its_rsssize, &its_sharedpages, &its_text, &its_lib, + &its_data, &its_dirtypages)) { + VSOMEIP_ERROR<< "memory_log_timer_cbk: error reading:" + << std::string(std::strerror(errno)); + } + std::fclose(its_file); + + struct timespec cputs, monots; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cputs); + clock_gettime(CLOCK_MONOTONIC, &monots); + + VSOMEIP_INFO << "memory usage: " + << "VmSize " << std::dec << its_size * its_pagesize << " kB, " + << "VmRSS " << std::dec << its_rsssize * its_pagesize << " kB, " + << "shared pages " << std::dec << its_sharedpages * its_pagesize << " kB, " + << "text " << std::dec << its_text * its_pagesize << " kB, " + << "data " << std::dec << its_data * its_pagesize << " kB " + << "| monotonic time: " << std::dec << monots.tv_sec << "." + << std::dec << monots.tv_nsec << " cpu time: " + << std::dec << cputs.tv_sec << "." << std::dec << cputs.tv_nsec + ; +#endif + + { + std::lock_guard<std::mutex> its_lock(memory_log_timer_mutex_); + boost::system::error_code ec; + memory_log_timer_.expires_from_now(std::chrono::seconds( + configuration_->get_log_memory_interval()), ec); + memory_log_timer_.async_wait( + std::bind(&routing_manager_impl::memory_log_timer_cbk, this, + std::placeholders::_1)); + } +} + +void routing_manager_impl::status_log_timer_cbk( + boost::system::error_code const & _error) { + if (_error) { + return; + } + + ep_mgr_impl_->print_status(); + { + std::lock_guard<std::mutex> its_lock(status_log_timer_mutex_); + boost::system::error_code ec; + status_log_timer_.expires_from_now(std::chrono::seconds( + configuration_->get_log_status_interval()), ec); + status_log_timer_.async_wait( + std::bind(&routing_manager_impl::status_log_timer_cbk, this, + std::placeholders::_1)); + } +} + +void +routing_manager_impl::on_unsubscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + remote_subscription_id_t _id) { + std::shared_ptr<eventgroupinfo> its_info + = find_eventgroup(_service, _instance, _eventgroup); + if (its_info) { + std::unique_lock<std::mutex> its_update_lock{update_remote_subscription_mutex_}; + const auto its_subscription = its_info->get_remote_subscription(_id); + if (its_subscription) { + its_info->remove_remote_subscription(_id); + + std::lock_guard<std::mutex> its_lock(remote_subscribers_mutex_); + remote_subscribers_[_service][_instance].erase(_client); + + if (its_info->get_remote_subscriptions().size() == 0) { + for (const auto &its_event : its_info->get_events()) { + bool has_remote_subscriber(false); + for (const auto &its_eventgroup : its_event->get_eventgroups()) { + const auto its_eventgroup_info + = find_eventgroup(_service, _instance, its_eventgroup); + if (its_eventgroup_info + && its_eventgroup_info->get_remote_subscriptions().size() > 0) { + has_remote_subscriber = true; + } + } + + if (!has_remote_subscriber && its_event->is_shadow()) { + its_event->unset_payload(); + } + } + } + } else { + VSOMEIP_ERROR << __func__ + << ": Unknown StopSubscribe " << std::dec << _id << " for eventgroup [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + } + } else { + VSOMEIP_ERROR << __func__ + << ": Received StopSubscribe for unknown eventgroup: (" + << std::hex << std::setfill('0') + << std::setw(4) << _client << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + } +} + +void routing_manager_impl::on_connect(const std::shared_ptr<endpoint>& _endpoint) { + (void)_endpoint; +} +void routing_manager_impl::on_disconnect(const std::shared_ptr<endpoint>& _endpoint) { + (void)_endpoint; +} +void routing_manager_impl::send_subscription( + const client_t _offering_client, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, const major_version_t _major, + const std::set<client_t> &_clients, + const remote_subscription_id_t _id) { + if (host_->get_client() == _offering_client) { + auto self = shared_from_this(); + for (const auto its_client : _clients) { + host_->on_subscription(_service, _instance, _eventgroup, its_client, + get_sec_client(), get_env(its_client), true, + [this, self, _service, _instance, _eventgroup, its_client, _id] + (const bool _is_accepted) { + try { + if (!_is_accepted) { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_subscribe_nack, + std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), + its_client, _service, _instance, + _eventgroup, false, _id); + io_.post(its_callback); + } else { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_subscribe_ack, + std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), + its_client, _service, _instance, + _eventgroup, ANY_EVENT, _id); + io_.post(its_callback); + } + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + }); + } + } else { // service hosted by local client + for (const auto its_client : _clients) { + if (stub_ && !stub_->send_subscribe(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, _major, ANY_EVENT, nullptr, _id)) { + try { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_subscribe_nack, + std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), + its_client, _service, _instance, _eventgroup, + true, _id); + io_.post(its_callback); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + } + } + } +} + +void routing_manager_impl::cleanup_server_endpoint( + service_t _service, const std::shared_ptr<endpoint>& _endpoint) { + if (_endpoint) { + // Clear service_instances_, check whether any service still + // uses this endpoint and clear server endpoint if no service + // remains using it + if (ep_mgr_impl_->remove_instance(_service, _endpoint.get())) { + if (ep_mgr_impl_->remove_server_endpoint( + _endpoint->get_local_port(), _endpoint->is_reliable())) { + // Stop endpoint (close socket) to release its async_handlers! + _endpoint->stop(); + } + } + } +} + +pending_remote_offer_id_t routing_manager_impl::pending_remote_offer_add( + service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(pending_remote_offers_mutex_); + if (++pending_remote_offer_id_ == 0) { + pending_remote_offer_id_++; + } + pending_remote_offers_[pending_remote_offer_id_] = std::make_pair(_service, + _instance); + return pending_remote_offer_id_; +} + +std::pair<service_t, instance_t> routing_manager_impl::pending_remote_offer_remove( + pending_remote_offer_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_remote_offers_mutex_); + std::pair<service_t, instance_t> ret = std::make_pair(ANY_SERVICE, + ANY_INSTANCE); + auto found_si = pending_remote_offers_.find(_id); + if (found_si != pending_remote_offers_.end()) { + ret = found_si->second; + pending_remote_offers_.erase(found_si); + } + return ret; +} + +void routing_manager_impl::on_resend_provided_events_response( + pending_remote_offer_id_t _id) { + const std::pair<service_t, instance_t> its_service = + pending_remote_offer_remove(_id); + if (its_service.first != ANY_SERVICE) { + // create server endpoint + std::shared_ptr<serviceinfo> its_info = find_service(its_service.first, + its_service.second); + if (its_info) { + its_info->set_ttl(DEFAULT_TTL); + init_service_info(its_service.first, its_service.second, true); + } + } +} + +void routing_manager_impl::print_stub_status() const { + if (stub_) + stub_->print_endpoint_status(); +} + +void routing_manager_impl::service_endpoint_connected( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, const std::shared_ptr<endpoint>& _endpoint, + bool _unreliable_only) { + + if (!_unreliable_only) { + // Mark only TCP-only and TCP+UDP services available here + // UDP-only services are already marked as available in add_routing_info + on_availability(_service, _instance, + availability_state_e::AS_AVAILABLE, + _major, _minor); + if (stub_) + stub_->on_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); + } + + auto its_timer = + std::make_shared<boost::asio::steady_timer>(io_); + boost::system::error_code ec; + its_timer->expires_from_now(std::chrono::milliseconds(3), ec); + if (!ec) { + its_timer->async_wait( + std::bind(&routing_manager_impl::call_sd_endpoint_connected, + std::static_pointer_cast<routing_manager_impl>( + shared_from_this()), std::placeholders::_1, + _service, _instance, _endpoint, its_timer)); + } else { + VSOMEIP_ERROR << __func__ << " " << ec.message(); + } +} + +void routing_manager_impl::service_endpoint_disconnected( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, const std::shared_ptr<endpoint>& _endpoint) { + (void)_endpoint; + on_availability(_service, _instance, + availability_state_e::AS_UNAVAILABLE, + _major, _minor); + if (stub_) + stub_->on_stop_offer_service(VSOMEIP_ROUTING_CLIENT, _service, _instance, + _major, _minor); + VSOMEIP_WARNING << __func__ << ": lost connection to remote service: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "]"; +} + +void +routing_manager_impl::send_unsubscription(client_t _offering_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + const std::set<client_t> &_removed, + remote_subscription_id_t _id) { + + (void)_major; // TODO: Remove completely? + + if (host_->get_client() == _offering_client) { + auto self = shared_from_this(); + for (const auto its_client : _removed) { + host_->on_subscription(_service, _instance, _eventgroup, + its_client, get_sec_client(), get_env(its_client),false, + [this, self, _service, _instance, _eventgroup, + its_client, _id] + (const bool _is_accepted) { + (void)_is_accepted; + try { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_unsubscribe_ack, + std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), + its_client, _service, _instance, _eventgroup, _id); + io_.post(its_callback); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + } + ); + } + } else { + for (const auto its_client : _removed) { + if (stub_ && !stub_->send_unsubscribe(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, ANY_EVENT, _id)) { + try { + const auto its_callback = std::bind( + &routing_manager_stub_host::on_unsubscribe_ack, + std::dynamic_pointer_cast<routing_manager_stub_host>(shared_from_this()), + its_client, _service, _instance, _eventgroup, _id); + io_.post(its_callback); + } catch (const std::exception &e) { + VSOMEIP_ERROR << __func__ << e.what(); + } + } + } + } +} + +void +routing_manager_impl::send_expired_subscription(client_t _offering_client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + const std::set<client_t> &_removed, + remote_subscription_id_t _id) { + + if (host_->get_client() == _offering_client) { + auto self = shared_from_this(); + for (const auto its_client : _removed) { + host_->on_subscription(_service, _instance, + _eventgroup, its_client, get_sec_client(), get_env(its_client), false, + [] (const bool _subscription_accepted){ + (void)_subscription_accepted; + }); + } + } else { + for (const auto its_client : _removed) { + if (stub_) + stub_->send_expired_subscription(find_local(_offering_client), its_client, + _service, _instance, _eventgroup, ANY_EVENT, _id); + } + } +} + +#ifndef VSOMEIP_DISABLE_SECURITY +bool +routing_manager_impl::update_security_policy_configuration( + uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy, + const std::shared_ptr<payload> &_payload, + const security_update_handler_t &_handler) { + + if (stub_) + return stub_->update_security_policy_configuration(_uid, _gid, + _policy, _payload, _handler); + + return false; +} + +bool +routing_manager_impl::remove_security_policy_configuration( + uid_t _uid, gid_t _gid, + const security_update_handler_t &_handler) { + + if (stub_) + return stub_->remove_security_policy_configuration(_uid, _gid, + _handler); + + return false; +} +#endif // !VSOMEIP_DISABLE_SECURITY + +bool routing_manager_impl::insert_event_statistics(service_t _service, instance_t _instance, + method_t _method, length_t _length) { + + static uint32_t its_max_messages = configuration_->get_statistics_max_messages(); + std::lock_guard<std::mutex> its_lock(message_statistics_mutex_); + const auto its_tuple = std::make_tuple(_service, _instance, _method); + const auto its_main_s = message_statistics_.find(its_tuple); + if (its_main_s != message_statistics_.end()) { + // increase counter and calculate moving average for payload length + its_main_s->second.avg_length_ = + (its_main_s->second.avg_length_ * its_main_s->second.counter_ + _length) / + (its_main_s->second.counter_ + 1); + its_main_s->second.counter_++; + + if (its_tuple == message_to_discard_) { + // check list for entry with least counter value + uint32_t its_min_count(0xFFFFFFFF); + auto its_tuple_to_discard = std::make_tuple(0xFFFF, 0xFFFF, 0xFFFF); + for (const auto &s : message_statistics_) { + if (s.second.counter_ < its_min_count) { + its_min_count = s.second.counter_; + its_tuple_to_discard = s.first; + } + } + if (its_min_count != 0xFFFF + && its_min_count < its_main_s->second.counter_) { + // update message to discard with current message + message_to_discard_ = its_tuple; + } + } + } else { + if (message_statistics_.size() < its_max_messages) { + message_statistics_[its_tuple] = {1, _length}; + message_to_discard_ = its_tuple; + } else { + // no slot empty + const auto it = message_statistics_.find(message_to_discard_); + if (it != message_statistics_.end() + && it->second.counter_ == 1) { + message_statistics_.erase(message_to_discard_); + message_statistics_[its_tuple] = {1, _length}; + message_to_discard_ = its_tuple; + } else { + // ignore message + ignored_statistics_counter_++; + return false; + } + } + } + return true; +} + +void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code const & _error) { + if (!_error) { + static uint32_t its_interval = configuration_->get_statistics_interval(); + its_interval = its_interval >= 1000 ? its_interval : 1000; + static uint32_t its_min_freq = configuration_->get_statistics_min_freq(); + std::stringstream its_log; + { + std::lock_guard<std::mutex> its_lock(message_statistics_mutex_); + for (const auto &s : message_statistics_) { + if (s.second.counter_ / (its_interval / 1000) > its_min_freq) { + uint16_t its_subscribed(0); + std::shared_ptr<event> its_event = find_event(std::get<0>(s.first), std::get<1>(s.first), std::get<2>(s.first)); + if (its_event) { + if (!its_event->is_provided()) { + its_subscribed = static_cast<std::uint16_t>(its_event->get_subscribers().size()); + } + } + its_log << std::hex << std::setfill('0') + << std::setw(4) << std::get<0>(s.first) << "." + << std::get<1>(s.first) << "." + << std::get<2>(s.first) << ": #=" + << std::dec << s.second.counter_ << " L=" + << s.second.avg_length_ << " S=" + << std::dec << its_subscribed << ", "; + } + } + + if (ignored_statistics_counter_) { + its_log << std::dec << " #ignored: " << ignored_statistics_counter_; + } + + message_statistics_.clear(); + message_to_discard_ = std::make_tuple(0x00, 0x00, 0x00); + ignored_statistics_counter_ = 0; + } + + if (its_log.str().length() > 0) { + VSOMEIP_INFO << "Received events statistics: [" << its_log.str() << "]"; + } + + { + std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_); + statistics_log_timer_.expires_from_now(std::chrono::milliseconds(its_interval)); + statistics_log_timer_.async_wait( + std::bind(&routing_manager_impl::statistics_log_timer_cbk, + this, std::placeholders::_1)); + } + } +} + +bool +routing_manager_impl::get_guest(client_t _client, + boost::asio::ip::address &_address, port_t &_port) const { + + return routing_manager_base::get_guest(_client, _address, _port); +} + +void +routing_manager_impl::add_guest(client_t _client, + const boost::asio::ip::address &_address, port_t _port) { + + routing_manager_base::add_guest(_client, _address, _port); +} + +void +routing_manager_impl::remove_guest(client_t _client) { + + routing_manager_base::remove_guest(_client); +} + +void routing_manager_impl::send_suspend() const { + if (stub_) + stub_->send_suspend(); +} + +void routing_manager_impl::clear_local_services() { + + std::lock_guard<std::mutex> its_lock(local_services_mutex_); + local_services_.clear(); +} + +void routing_manager_impl::register_message_acceptance_handler( + const message_acceptance_handler_t& _handler) { + message_acceptance_handler_ = _handler; +} + +void +routing_manager_impl::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<eventgroupinfo> > > >its_eventgroups; + { + std::lock_guard<std::mutex> its_lock(eventgroups_mutex_); + its_eventgroups = eventgroups_; + } + for (const auto &its_service : its_eventgroups) { + for (const auto &its_instance : its_service.second) { + for (const auto &its_eventgroup : its_instance.second) { + const auto its_info = its_eventgroup.second; + for (auto its_subscription + : its_info->get_remote_subscriptions()) { + auto its_definition = its_subscription->get_reliable(); + if (its_definition + && its_definition->get_address() == _remote_address + && its_definition->get_port() == _remote_port + && its_definition->get_remote_port() == _local_port) { + + VSOMEIP_INFO << __func__ + << ": Removing subscription to [" + << std::hex << std::setfill('0') + << std::setw(4) << its_info->get_service() << "." + << std::setw(4) << its_info->get_instance() << "." + << std::setw(4) << its_info->get_eventgroup() + << "] from target " + << its_definition->get_address() << ":" + << std::dec << its_definition->get_port() + << " reliable=true"; + + on_remote_unsubscribe(its_subscription); + } + } + } + } + } +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_stub.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_stub.cpp new file mode 100644 index 00000000000..a5c7ece8673 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/routing_manager_stub.cpp @@ -0,0 +1,2637 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <functional> +#include <iomanip> +#include <forward_list> + +#include <boost/system/error_code.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/error.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/structured_types.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/routing_manager_stub.hpp" +#include "../include/routing_manager_stub_host.hpp" +#include "../include/remote_subscription.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint_manager_impl.hpp" +#include "../../endpoints/include/netlink_connector.hpp" +#include "../../protocol/include/deregister_application_command.hpp" +#include "../../protocol/include/distribute_security_policies_command.hpp" +#include "../../protocol/include/dummy_command.hpp" +#include "../../protocol/include/expire_command.hpp" +#include "../../protocol/include/offer_service_command.hpp" +#include "../../protocol/include/offered_services_request_command.hpp" +#include "../../protocol/include/offered_services_response_command.hpp" +#include "../../protocol/include/ping_command.hpp" +#include "../../protocol/include/pong_command.hpp" +#include "../../protocol/include/register_application_command.hpp" +#include "../../protocol/include/register_events_command.hpp" +#include "../../protocol/include/registered_ack_command.hpp" +#include "../../protocol/include/release_service_command.hpp" +#include "../../protocol/include/remove_security_policy_command.hpp" +#include "../../protocol/include/remove_security_policy_response_command.hpp" +#include "../../protocol/include/request_service_command.hpp" +#include "../../protocol/include/resend_provided_events_command.hpp" +#include "../../protocol/include/routing_info_command.hpp" +#include "../../protocol/include/send_command.hpp" +#include "../../protocol/include/stop_offer_service_command.hpp" +#include "../../protocol/include/subscribe_ack_command.hpp" +#include "../../protocol/include/subscribe_command.hpp" +#include "../../protocol/include/subscribe_nack_command.hpp" +#include "../../protocol/include/suspend_command.hpp" +#include "../../protocol/include/unregister_event_command.hpp" +#include "../../protocol/include/unsubscribe_ack_command.hpp" +#include "../../protocol/include/unsubscribe_command.hpp" +#include "../../protocol/include/update_security_credentials_command.hpp" +#include "../../protocol/include/update_security_policy_command.hpp" +#include "../../protocol/include/update_security_policy_response_command.hpp" +#include "../../protocol/include/config_command.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../security/include/security.hpp" +#include "../../utility/include/bithelper.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +routing_manager_stub::routing_manager_stub( + routing_manager_stub_host *_host, + const std::shared_ptr<configuration>& _configuration) : + host_(_host), + io_(_host->get_io()), + watchdog_timer_(_host->get_io()), + client_id_timer_(_host->get_io()), + root_(nullptr), + local_receiver_(nullptr), + configuration_(_configuration), + is_socket_activated_(false), + client_registration_running_(false), + max_local_message_size_(configuration_->get_max_message_size_local()), + configured_watchdog_timeout_(configuration_->get_watchdog_timeout()), + pinged_clients_timer_(io_), + pending_security_update_id_(0) +#if defined(__linux__) || defined(ANDROID) + , is_local_link_available_(false) +#endif +{ +} + +routing_manager_stub::~routing_manager_stub() { +} + +void routing_manager_stub::init() { + + init_routing_endpoint(); + + std::string its_env; + char its_hostname[1024]; + if (gethostname(its_hostname, sizeof(its_hostname)) == 0) + its_env = its_hostname; + host_->set_client_host(its_env); +} + +void routing_manager_stub::start() { + { + std::lock_guard<std::mutex> its_lock(used_client_ids_mutex_); + used_client_ids_ = utility::get_used_client_ids(configuration_->get_network()); + // Wait VSOMEIP_MAX_CONNECT_TIMEOUT * 2 and expect after that time + // that all client_ids are used have to be connected to the routing. + // Otherwise they can be marked as "erroneous client". + client_id_timer_.expires_from_now(std::chrono::milliseconds(VSOMEIP_MAX_CONNECT_TIMEOUT * 2)); + client_id_timer_.async_wait( + std::bind( + &routing_manager_stub::on_client_id_timer_expired, + std::dynamic_pointer_cast<routing_manager_stub>(shared_from_this()), + std::placeholders::_1)); + } + +#if defined(__linux__) || defined(ANDROID) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + if (!root_) { + // application has been stopped and started again + init_routing_endpoint(); + } + if (root_) { + root_->start(); + } +#if defined(__linux__) || defined(ANDROID) + } else { + if (local_link_connector_) + local_link_connector_->start(); +#endif + } + + client_registration_running_ = true; + client_registration_thread_ = std::make_shared<std::thread>( + std::bind(&routing_manager_stub::client_registration_func, this)); + + if (configuration_->is_watchdog_enabled()) { + VSOMEIP_INFO << "Watchdog is enabled : Timeout in ms = " + << configuration_->get_watchdog_timeout() + << " : Allowed missing pongs = " + << configuration_->get_allowed_missing_pongs() + << "."; + start_watchdog(); + } else { + VSOMEIP_INFO << "Watchdog is disabled!"; + } + + { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + routing_info_[host_->get_client()].first = 0; + } +} + +void routing_manager_stub::stop() { + { + std::lock_guard<std::mutex> its_lock(client_registration_mutex_); + client_registration_running_ = false; + client_registration_condition_.notify_one(); + } + if (client_registration_thread_->joinable()) { + client_registration_thread_->join(); + } + + { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + watchdog_timer_.cancel(); + } + + { + std::lock_guard<std::mutex> its_lock(used_client_ids_mutex_); + client_id_timer_.cancel(); + } + + bool is_local_routing(configuration_->is_local_routing()); + +#if defined(__linux__) || defined(ANDROID) + if (local_link_connector_) + local_link_connector_->stop(); +#endif // __linux__ || ANDROID + + if (!is_socket_activated_) { + root_->stop(); + root_ = nullptr; + + if (is_local_routing) { + std::stringstream its_endpoint_path; + its_endpoint_path << utility::get_base_path(configuration_->get_network()) + << std::hex << VSOMEIP_ROUTING_CLIENT; + #ifdef _WIN32 + ::_unlink(its_endpoint_path.str().c_str()); + #else + if (-1 == ::unlink(its_endpoint_path.str().c_str())) { + VSOMEIP_ERROR << "routing_manager_stub::stop() unlink failed (" + << its_endpoint_path.str() << "): "<< std::strerror(errno); + } + #endif + } + } + + if (local_receiver_) { + local_receiver_->stop(); + local_receiver_ = nullptr; + + if (is_local_routing) { + std::stringstream its_local_receiver_path; + its_local_receiver_path << utility::get_base_path(configuration_->get_network()) + << std::hex << host_->get_client(); +#ifdef _WIN32 + ::_unlink(its_local_receiver_path.str().c_str()); +#else + if (-1 == ::unlink(its_local_receiver_path.str().c_str())) { + VSOMEIP_ERROR << "routing_manager_stub::stop() unlink (local receiver) failed (" + << its_local_receiver_path.str() << "): "<< std::strerror(errno); + } +#endif + } + } +} + +void routing_manager_stub::on_message(const byte_t *_data, length_t _size, + endpoint *_receiver, bool _is_multicast, + client_t _bound_client, const vsomeip_sec_client_t *_sec_client, + const boost::asio::ip::address &_remote_address, + std::uint16_t _remote_port) { + + (void)_receiver; + (void)_is_multicast; + (void)_remote_address; + (void) _remote_port; +#if 0 + std::stringstream msg; + msg << "rms::on_message: "; + for (length_t i = 0; i < _size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + client_t its_client; + protocol::id_e its_id; + std::string its_client_endpoint; + service_t its_service; + instance_t its_instance; + method_t its_method; + eventgroup_t its_eventgroup; + event_t its_notifier; + major_version_t its_major; + minor_version_t its_minor; + std::shared_ptr<payload> its_payload; + bool is_reliable(false); + client_t its_subscriber; + uint8_t its_check_status(0); + std::uint16_t its_subscription_id(PENDING_SUBSCRIPTION_ID); + port_t its_port(ILLEGAL_PORT); + + std::vector<byte_t> its_buffer(_data, _data + _size); + protocol::error_e its_error; + + // Use dummy command to deserialize id and client. + protocol::dummy_command its_base_command; + its_base_command.deserialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << __func__ + << ": deserialization of command and client identifier failed (" + << std::dec << static_cast<int>(its_error) + << ")"; + return; + } + + its_client = its_base_command.get_client(); + its_id = its_base_command.get_id(); + + if (configuration_->is_security_enabled() + && configuration_->is_local_routing() + && _bound_client != its_client) { + VSOMEIP_WARNING << "vSomeIP Security: routing_manager_stub::on_message: " + << "Routing Manager received a message from client " + << std::hex << std::setw(4) << std::setfill('0') + << its_client << " with command " << (uint32_t)its_id + << " which doesn't match the bound client " + << std::setw(4) << std::setfill('0') << _bound_client + << " ~> skip message!"; + return; + } + + switch (its_id) { + + case protocol::id_e::REGISTER_APPLICATION_ID: + { + protocol::register_application_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + update_registration(its_command.get_client(), + registration_type_e::REGISTER, + _remote_address, its_command.get_port()); + else + VSOMEIP_ERROR << __func__ + << ": deserializing register application failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::DEREGISTER_APPLICATION_ID: + { + protocol::deregister_application_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) + update_registration(its_command.get_client(), + registration_type_e::DEREGISTER, + _remote_address, its_port); + else + VSOMEIP_ERROR << __func__ + << ": deserializing register application failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::PONG_ID: + { + protocol::pong_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_pong(its_client); + VSOMEIP_TRACE << "PONG(" + << std::hex << std::setw(4) << std::setfill('0') + << its_client << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing pong failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::OFFER_SERVICE_ID: + { + protocol::offer_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_major = its_command.get_major(); + its_minor = its_command.get_minor(); + + if (VSOMEIP_SEC_OK == configuration_->get_security()->is_client_allowed_to_offer( + _sec_client, its_service, its_instance)) { + host_->offer_service(its_client, its_service, its_instance, + its_major, its_minor); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: isn't allowed to offer " + << "the following service/instance " << its_service << "/" << its_instance + << " ~> Skip offer!"; + } + } else + VSOMEIP_ERROR << __func__ + << ": deserializing offer service failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::STOP_OFFER_SERVICE_ID: + { + protocol::stop_offer_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_major = its_command.get_major(); + its_minor = its_command.get_minor(); + + host_->stop_offer_service(its_client, + its_service, its_instance, + its_major, its_minor); + } else + VSOMEIP_ERROR << __func__ + << ": deserializing stop offer service failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ID: + { + protocol::subscribe_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_major = its_command.get_major(); + its_notifier = its_command.get_event(); + auto its_filter = its_command.get_filter(); + + if (its_notifier == ANY_EVENT) { + if (host_->is_subscribe_to_any_event_allowed(_sec_client, its_client, its_service, + its_instance, its_eventgroup)) { + host_->subscribe(its_client, _sec_client, its_service, its_instance, + its_eventgroup, its_major, its_notifier, its_filter); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/ANY_EVENT" + << " which violates the security policy ~> Skip subscribe!"; + } + } else { + if (VSOMEIP_SEC_OK == configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_notifier)) { + host_->subscribe(its_client, _sec_client, its_service, its_instance, + its_eventgroup, its_major, its_notifier, its_filter); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " subscribes to service/instance/event " + << its_service << "/" << its_instance << "/" << its_notifier + << " which violates the security policy ~> Skip subscribe!"; + } + } + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::UNSUBSCRIBE_ID: + { + protocol::unsubscribe_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_notifier = its_command.get_event(); + + host_->unsubscribe(its_client, _sec_client, + its_service, its_instance, its_eventgroup, its_notifier); + } else + VSOMEIP_ERROR << __func__ + << ": deserializing unsubscribe failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SUBSCRIBE_ACK_ID: + { + protocol::subscribe_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscriber = its_command.get_subscriber(); + its_notifier = its_command.get_event(); + its_subscription_id = its_command.get_pending_id(); + + host_->on_subscribe_ack(its_subscriber, its_service, + its_instance, its_eventgroup, its_notifier, its_subscription_id); + + VSOMEIP_INFO << "SUBSCRIBE ACK(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_notifier << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe ack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::SUBSCRIBE_NACK_ID: + { + protocol::subscribe_nack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscriber = its_command.get_subscriber(); + its_notifier = its_command.get_event(); + its_subscription_id = its_command.get_pending_id(); + + host_->on_subscribe_nack(its_subscriber, its_service, + its_instance, its_eventgroup, false, its_subscription_id); + + VSOMEIP_INFO << "SUBSCRIBE NACK(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "." + << std::setw(4) << its_notifier << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing subscribe nack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::UNSUBSCRIBE_ACK_ID: + { + protocol::unsubscribe_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + its_service = its_command.get_service(); + its_instance = its_command.get_instance(); + its_eventgroup = its_command.get_eventgroup(); + its_subscription_id = its_command.get_pending_id(); + + host_->on_unsubscribe_ack(its_client, its_service, + its_instance, its_eventgroup, its_subscription_id); + + VSOMEIP_INFO << "UNSUBSCRIBE ACK(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup << "]"; + } else + VSOMEIP_ERROR << __func__ + << ": deserializing unsubscribe ack failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::SEND_ID: + { + protocol::send_command its_command(its_id); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_message_data(its_command.get_message()); + if (its_message_data.size() > VSOMEIP_MESSAGE_TYPE_POS) { + + its_service = bithelper::read_uint16_be(&its_message_data[VSOMEIP_SERVICE_POS_MIN]); + its_method = bithelper::read_uint16_be(&its_message_data[VSOMEIP_METHOD_POS_MIN]); + its_client = bithelper::read_uint16_be(&its_message_data[VSOMEIP_CLIENT_POS_MIN]); + + its_instance = its_command.get_instance(); + is_reliable = its_command.is_reliable(); + its_check_status = its_command.get_status(); + + // Allow response messages from local proxies as answer to remote requests + // but check requests sent by local proxies to remote against policy. + if (utility::is_request(its_message_data[VSOMEIP_MESSAGE_TYPE_POS])) { + if (VSOMEIP_SEC_OK != configuration_->get_security()->is_client_allowed_to_access_member( + _sec_client, its_service, its_instance, its_method)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_client + << " : routing_manager_stub::on_message: " + << " isn't allowed to send a request to service/instance/method " + << its_service << "/" << its_instance << "/" << its_method + << " ~> Skip message!"; + return; + } + } + // reduce by size of instance, flush, reliable, client and is_valid_crc flag + uint32_t its_contained_size = bithelper::read_uint32_be(&its_message_data[VSOMEIP_LENGTH_POS_MIN]); + if (its_message_data.size() != its_contained_size + VSOMEIP_SOMEIP_HEADER_SIZE) { + VSOMEIP_WARNING << "Received a SEND command containing message with invalid size -> skip!"; + break; + } + host_->on_message(its_service, its_instance, + &its_message_data[0], length_t(its_message_data.size()), + is_reliable, _bound_client, _sec_client, its_check_status, false); + } + } + break; + } + + case protocol::id_e::NOTIFY_ID: + case protocol::id_e::NOTIFY_ONE_ID: + { + protocol::send_command its_command(its_id); + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + auto its_message_data(its_command.get_message()); + if (its_message_data.size() > VSOMEIP_MESSAGE_TYPE_POS) { + + its_client = its_command.get_target(); + its_service = bithelper::read_uint16_be(&its_message_data[VSOMEIP_SERVICE_POS_MIN]); + its_instance = its_command.get_instance(); + + uint32_t its_contained_size = bithelper::read_uint32_be(&its_message_data[VSOMEIP_LENGTH_POS_MIN]); + + if (its_message_data.size() != its_contained_size + VSOMEIP_SOMEIP_HEADER_SIZE) { + VSOMEIP_WARNING << "Received a NOTIFY command containing message with invalid size -> skip!"; + break; + } + + host_->on_notification(its_client, its_service, its_instance, + &its_message_data[0], length_t(its_message_data.size()), + its_id == protocol::id_e::NOTIFY_ONE_ID); + break; + } + } + break; + } + + case protocol::id_e::REQUEST_SERVICE_ID: + { + protocol::request_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + its_client = its_command.get_client(); + auto its_requests = its_command.get_services(); + + std::set<protocol::service> its_allowed_requests; + for (const auto &r : its_requests) { + if (VSOMEIP_SEC_OK == configuration_->get_security()->is_client_allowed_to_request( + _sec_client, r.service_, r.instance_)) { + host_->request_service(its_client, + r.service_, r.instance_, r.major_, r.minor_); + its_allowed_requests.insert(r); + } + } + if (configuration_->is_security_enabled()) { + handle_credentials(its_client, its_allowed_requests); + } + handle_requests(its_client, its_allowed_requests); + } else + VSOMEIP_ERROR << __func__ << ": request service deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + + break; + } + + case protocol::id_e::RELEASE_SERVICE_ID: + { + protocol::release_service_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + host_->release_service(its_command.get_client(), + its_command.get_service(), its_command.get_instance()); + } else + VSOMEIP_ERROR << __func__ << ": release service deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::REGISTER_EVENT_ID: + { + protocol::register_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + its_client = its_command.get_client(); + for(std::size_t i = 0; i < its_command.get_num_registrations(); i++) { + protocol::register_event register_event; + if (!its_command.get_registration_at(i, register_event)) { + continue; + } + + its_service = register_event.get_service(); + its_instance = register_event.get_instance(); + + if (register_event.is_provided() + && !configuration_->is_offered_remote(its_service, its_instance)) { + continue; + } + + host_->register_shadow_event(its_client, + its_service, its_instance, + register_event.get_event(), register_event.get_eventgroups(), + register_event.get_event_type(), register_event.get_reliability(), + register_event.is_provided(), register_event.is_cyclic()); + + VSOMEIP_INFO << "REGISTER EVENT(" + << std::hex << std::setfill('0') + << std::setw(4) << its_client << "): [" + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << register_event.get_event() + << ":eventtype=" << std::dec << (int)register_event.get_event_type() + << ":is_provided=" << std::boolalpha << register_event.is_provided() + << ":reliable=" << (int)register_event.get_reliability() << "]"; + } + + + } else + VSOMEIP_ERROR << __func__ << ": register event deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::UNREGISTER_EVENT_ID: + { + protocol::unregister_event_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + host_->unregister_shadow_event(its_command.get_client(), + its_command.get_service(), its_command.get_instance(), + its_command.get_event(), its_command.is_provided()); + + VSOMEIP_INFO << "UNREGISTER EVENT(" + << std::hex << std::setfill('0') + << std::setw(4) << its_command.get_client() << "): [" + << std::setw(4) << its_command.get_service() << "." + << std::setw(4) << its_command.get_instance() << "." + << std::setw(4) << its_command.get_event() + << ":is_provider=" << std::boolalpha << its_command.is_provided() << "]"; + } else + VSOMEIP_ERROR << __func__ << ": unregister event deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::REGISTERED_ACK_ID: + { + protocol::registered_ack_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + VSOMEIP_INFO << "REGISTERED_ACK(" + << std::hex << std::setw(4) << std::setfill('0') + << its_command.get_client() << ")"; + } else + VSOMEIP_ERROR << __func__ << ": registered ack deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::OFFERED_SERVICES_REQUEST_ID: + { + protocol::offered_services_request_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + + on_offered_service_request(its_command.get_client(), its_command.get_offer_type()); + } else + VSOMEIP_ERROR << __func__ << ": offer service request deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::RESEND_PROVIDED_EVENTS_ID: + { + protocol::resend_provided_events_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + host_->on_resend_provided_events_response(its_command.get_remote_offer_id()); + VSOMEIP_INFO << "RESEND_PROVIDED_EVENTS(" + << std::hex << std::setw(4) << std::setfill('0') << its_client << ")"; + } else + VSOMEIP_ERROR << __func__ << ": resend provided events deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } +#ifndef VSOMEIP_DISABLE_SECURITY + case protocol::id_e::UPDATE_SECURITY_POLICY_RESPONSE_ID: + { + protocol::update_security_policy_response_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_security_update_response(its_command.get_update_id(), its_client); + } else + VSOMEIP_ERROR << __func__ << ": update security policy deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } + + case protocol::id_e::REMOVE_SECURITY_POLICY_RESPONSE_ID: + { + protocol::remove_security_policy_response_command its_command; + its_command.deserialize(its_buffer, its_error); + if (its_error == protocol::error_e::ERROR_OK) { + on_security_update_response(its_command.get_update_id(), its_client); + } else + VSOMEIP_ERROR << __func__ << ": update security policy deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + break; + } +#endif // !VSOMEIP_DISABLE_SECURITY + case protocol::id_e::CONFIG_ID: { + protocol::config_command its_command; + protocol::error_e its_command_error; + its_command.deserialize(its_buffer, its_command_error); + if (its_command_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ << ": config command deserialization failed (" << std::dec + << static_cast<int>(its_command_error) << ")"; + break; + } + if (its_command.contains("hostname")) { + add_known_client(its_command.get_client(), its_command.at("hostname")); + } + break; + } + default: + VSOMEIP_WARNING << __func__ << ": Received an unhandled command (" + << std::dec << static_cast<int>(its_id) << ")"; + } +} + +void routing_manager_stub::add_known_client(client_t _client, const std::string &_client_host) { + host_->add_known_client(_client, _client_host); +} + +void routing_manager_stub::on_register_application(client_t _client) { + + auto endpoint = host_->find_local(_client); + if (endpoint) { + VSOMEIP_WARNING << "Reregistering application: " << std::hex << _client + << ". Last registration might have been taken too long."; + endpoint->stop(); + endpoint->start(); + } else { + endpoint = host_->find_or_create_local(_client); + { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + routing_info_[_client].first = 0; + } +#ifndef VSOMEIP_DISABLE_SECURITY + if (configuration_->is_local_routing()) { + vsomeip_sec_client_t its_sec_client; + std::set<std::shared_ptr<policy> > its_policies; + + bool has_mapping = configuration_->get_policy_manager() + ->get_client_to_sec_client_mapping(_client, its_sec_client); + if (has_mapping) { + if (its_sec_client.port == VSOMEIP_SEC_PORT_UNUSED) { + get_requester_policies(its_sec_client.user, + its_sec_client.group, its_policies); + } + + if (!its_policies.empty()) + send_requester_policies({ _client }, its_policies); + } + } +#endif // !VSOMEIP_DISABLE_SECURITY + } +} + +void routing_manager_stub::on_deregister_application(client_t _client) { + std::vector< + std::tuple<service_t, instance_t, + major_version_t, minor_version_t>> services_to_report; + { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + auto its_info = routing_info_.find(_client); + if (its_info != routing_info_.end()) { + for (const auto &its_service : its_info->second.second) { + for (const auto &its_instance : its_service.second) { + const auto its_version = its_instance.second; + services_to_report.push_back( + std::make_tuple(its_service.first, + its_instance.first, its_version.first, + its_version.second)); + } + } + } + routing_info_.erase(_client); + } + for (const auto &s : services_to_report) { + host_->on_availability(std::get<0>(s), std::get<1>(s), + availability_state_e::AS_UNAVAILABLE, + std::get<2>(s), std::get<3>(s)); + host_->on_stop_offer_service(_client, std::get<0>(s), std::get<1>(s), + std::get<2>(s), std::get<3>(s)); + } +} + +void +routing_manager_stub::on_offered_service_request(client_t _client, + offer_type_e _offer_type) { + + protocol::offered_services_response_command its_command; + its_command.set_client(_client); + + for (const auto& found_client : routing_info_) { + // skip services which are offered on remote hosts + if (found_client.first != VSOMEIP_ROUTING_CLIENT) { + for (const auto &s : found_client.second.second) { + for (const auto &i : s.second) { + uint16_t its_reliable_port + = configuration_->get_reliable_port(s.first, i.first); + uint16_t its_unreliable_port + = configuration_->get_unreliable_port(s.first, i.first); + bool has_port = (its_reliable_port != ILLEGAL_PORT + || its_unreliable_port != ILLEGAL_PORT); + + if (_offer_type == offer_type_e::OT_ALL + || (_offer_type == offer_type_e::OT_LOCAL && !has_port) + || (_offer_type == offer_type_e::OT_REMOTE && has_port)) { + + protocol::service its_service(s.first, i.first, + i.second.first, i.second.second); + its_command.add_service(its_service); + } + } + } + } + } + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) + its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } +} + +void routing_manager_stub::client_registration_func(void) { +#if defined(__linux__) || defined(ANDROID) + { + std::stringstream s; + s << std::hex << std::setw(4) << std::setfill('0') + << host_->get_client() << "_client_reg"; + pthread_setname_np(pthread_self(),s.str().c_str()); + } +#endif + std::unique_lock<std::mutex> its_lock(client_registration_mutex_); + while (client_registration_running_) { + while (!pending_client_registrations_.size() && client_registration_running_) { + client_registration_condition_.wait(its_lock); + } + + std::map<client_t, std::vector<registration_type_e>> its_registrations( + pending_client_registrations_); + pending_client_registrations_.clear(); + its_lock.unlock(); + + for (const auto& r : its_registrations) { + for (auto b : r.second) { + if (b == registration_type_e::REGISTER) { + on_register_application(r.first); + } else { + on_deregister_application(r.first); + } + // Inform (de)registered client. All others will be informed after + // the client acknowledged its registered state! + // Don't inform client if we deregister because of an client + // endpoint error to avoid writing in an already closed socket + if (b != registration_type_e::DEREGISTER_ON_ERROR) { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + add_connection(r.first, r.first); + protocol::routing_info_entry its_entry; + its_entry.set_client(r.first); + if (b == registration_type_e::REGISTER) { + boost::asio::ip::address its_address; + port_t its_port; + + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + if (host_->get_guest(r.first, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } +#ifndef VSOMEIP_DISABLE_SECURITY + // distribute updated security config to new clients + send_cached_security_policies(r.first); +#endif // !VSOMEIP_DISABLE_SECURITY + } else { + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT); + } + send_client_routing_info(r.first, its_entry); + } + if (b != registration_type_e::REGISTER) { + { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + auto find_connections = connection_matrix_.find(r.first); + if (find_connections != connection_matrix_.end()) { + for (auto its_client : find_connections->second) { + if (its_client != r.first && + its_client != VSOMEIP_ROUTING_CLIENT && + its_client != get_client()) { + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_DELETE_CLIENT); + its_entry.set_client(r.first); + send_client_routing_info(its_client, its_entry); + } + } + remove_source(r.first); + } + for (const auto &its_connections : connection_matrix_) { + remove_connection(its_connections.first, r.first); + } + service_requests_.erase(r.first); + } + // Don't remove client ID to UID maping as same client + // could have passed its credentials again + host_->remove_local(r.first, false); + utility::release_client_id(configuration_->get_network(), r.first); + } + } + } + its_lock.lock(); + } +} + +void routing_manager_stub::init_routing_endpoint() { + +#if defined(__linux__) || defined(ANDROID) + if (configuration_->is_local_routing()) { +#else + { +#endif // __linux__ || ANDROID + bool is_successful = host_->get_endpoint_manager()->create_routing_root( + root_, is_socket_activated_, shared_from_this()); + + if (!is_successful) { + VSOMEIP_WARNING << "Routing root creating (partially) failed. Please check your configuration."; + } +#if defined(__linux__) || defined(ANDROID) + } else { + auto its_host_address = configuration_->get_routing_host_address(); + local_link_connector_ = std::make_shared<netlink_connector>( + io_, its_host_address, boost::asio::ip::address(), false); // routing host doesn't need link up + if (local_link_connector_) { + local_link_connector_->register_net_if_changes_handler( + std::bind(&routing_manager_stub::on_net_state_change, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } +#endif // __linux__ || ANDROID + } +} + +#if defined(__linux__) || defined(ANDROID) +void +routing_manager_stub::on_net_state_change( + bool _is_interface, const std::string &_name, bool _is_available) { + + VSOMEIP_INFO << __func__ + << "("<< std::hex << std::this_thread::get_id() << "): " + << std::boolalpha << _is_interface << " " + << _name << " " + << std::boolalpha << _is_available; + + if (_is_interface) { + if (_is_available) { + if (!is_local_link_available_) { + is_local_link_available_ = true; + if (!root_) + (void)host_->get_endpoint_manager()->create_routing_root( + root_, is_socket_activated_, shared_from_this()); + if (root_) { + VSOMEIP_INFO << __func__ + << ": Starting routing root."; + root_->start(); + } else + VSOMEIP_WARNING << "Routing root creating (partially) failed. " + "Please check your configuration."; + } + } else { + if (is_local_link_available_) { + + VSOMEIP_INFO << __func__ + << ": Stopping routing root."; + root_->stop(); + + routing_info_.clear(); + host_->clear_local_services(); + + is_local_link_available_ = false; + } + } + } +} +#endif // __linux__ || ANDROID + +void routing_manager_stub::on_offer_service(client_t _client, + service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { + if (_client == host_->get_client()) { + create_local_receiver(); + } + + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + routing_info_[_client].second[_service][_instance] = std::make_pair(_major, _minor); + if (configuration_->is_security_enabled()) { + distribute_credentials(_client, _service, _instance); + } + inform_requesters(_client, _service, _instance, _major, _minor, + protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE, true); +} + +void routing_manager_stub::on_stop_offer_service(client_t _client, + service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + auto found_client = routing_info_.find(_client); + if (found_client != routing_info_.end()) { + auto found_service = found_client->second.second.find(_service); + if (found_service != found_client->second.second.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_version = found_instance->second; + if( _major == found_version.first && _minor == found_version.second) { + found_service->second.erase(_instance); + if (0 == found_service->second.size()) { + found_client->second.second.erase(_service); + } + inform_requesters(_client, _service, _instance, _major, _minor, + protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE, false); + } else if( _major == DEFAULT_MAJOR && _minor == DEFAULT_MINOR) { + found_service->second.erase(_instance); + if (0 == found_service->second.size()) { + found_client->second.second.erase(_service); + } + inform_requesters(_client, _service, _instance, _major, _minor, + protocol::routing_info_entry_type_e::RIE_DELETE_SERVICE_INSTANCE, false); + } + } + } + } +} + +void routing_manager_stub::send_client_credentials(const client_t _target, + std::set<std::pair<uid_t, gid_t>> &_credentials) { + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_target); + if (its_endpoint) { + protocol::update_security_credentials_command its_command; + its_command.set_client(_target); + its_command.set_credentials(_credentials); + +#if 0 + std::stringstream msg; + msg << "rms::send_credentials_info to (" << std::hex << _target << "): "; + for (uint32_t i = 0; i < its_size; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)its_command[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + if(its_buffer.size() <= max_local_message_size_ + || VSOMEIP_MAX_LOCAL_MESSAGE_SIZE == 0) { + its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": Credentials info exceeds maximum message size: Can't send!"; + + } else + VSOMEIP_ERROR << __func__ + << ": update security credentials command serialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": Sending credentials to client [" + << std::hex << std::setw(4) << std::setfill('0') + << _target + << "] failed"; +} + +void routing_manager_stub::send_client_routing_info(const client_t _target, + protocol::routing_info_entry &_entry) { + + std::vector<protocol::routing_info_entry> its_entries; + its_entries.emplace_back(_entry); + send_client_routing_info(_target, std::move(its_entries)); +} + +void routing_manager_stub::send_client_routing_info(const client_t _target, + std::vector<protocol::routing_info_entry> &&_entries) { + + auto its_target_endpoint = host_->find_local(_target); + if (its_target_endpoint) { + + protocol::routing_info_command its_command; + its_command.set_client(get_client()); + its_command.set_entries(std::move(_entries)); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + its_target_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": routing info command serialization failed (" + << static_cast<int>(its_error) + << ")"; + } else + VSOMEIP_ERROR << __func__ + << ": Sending routing info to client [" + << std::hex << std::setw(4) << std::setfill('0') + << _target + << "] failed"; +} + +void routing_manager_stub::distribute_credentials(client_t _hoster, service_t _service, instance_t _instance) { + std::set<std::pair<uid_t, gid_t>> its_credentials; + std::set<client_t> its_requesting_clients; + // search for clients which shall receive the credentials + for (auto its_requesting_client : service_requests_) { + auto its_service = its_requesting_client.second.find(_service); + if (its_service != its_requesting_client.second.end()) { + if (its_service->second.find(_instance) != its_service->second.end() + || its_service->second.find(ANY_INSTANCE) != its_service->second.end()) { + its_requesting_clients.insert(its_requesting_client.first); + } + } + } + + // search for UID / GID linked with the client ID that offers the requested services + vsomeip_sec_client_t its_sec_client; + if (configuration_->get_policy_manager()->get_client_to_sec_client_mapping(_hoster, its_sec_client)) { + std::pair<uid_t, gid_t> its_uid_gid; + its_uid_gid.first = its_sec_client.user; + its_uid_gid.second = its_sec_client.group; + its_credentials.insert(its_uid_gid); + for (auto its_requesting_client : its_requesting_clients) { + vsomeip_sec_client_t its_requester_sec_client; + if (configuration_->get_policy_manager()->get_client_to_sec_client_mapping( + its_requesting_client, its_requester_sec_client)) { + if (!utility::compare(its_sec_client, its_requester_sec_client)) + send_client_credentials(its_requesting_client, its_credentials); + } + } + } +} + +void routing_manager_stub::inform_requesters(client_t _hoster, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor, + protocol::routing_info_entry_type_e _type, bool _inform_service) { + + boost::asio::ip::address its_address; + port_t its_port; + + for (auto its_client : service_requests_) { + auto its_service = its_client.second.find(_service); + if (its_service != its_client.second.end()) { + if (its_service->second.find(_instance) != its_service->second.end() + || its_service->second.find(ANY_INSTANCE) != its_service->second.end()) { + if (_inform_service) { + if (_hoster != VSOMEIP_ROUTING_CLIENT && + _hoster != host_->get_client()) { + if (!is_connected(_hoster, its_client.first)) { + add_connection(_hoster, its_client.first); + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(its_client.first); + if (host_->get_guest(its_client.first, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + send_client_routing_info(_hoster, its_entry); + } + } + } + if (its_client.first != VSOMEIP_ROUTING_CLIENT && + its_client.first != get_client()) { + add_connection(its_client.first, _hoster); + protocol::routing_info_entry its_entry; + its_entry.set_type(_type); + its_entry.set_client(_hoster); + if ((_type == protocol::routing_info_entry_type_e::RIE_ADD_CLIENT + || _type == protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE) + && host_->get_guest(_hoster, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ _service, _instance, _major, _minor} ); + send_client_routing_info(its_client.first, its_entry); + } + } + } + } +} + +void routing_manager_stub::broadcast(const std::vector<byte_t> &_command) const { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + for (const auto& a : routing_info_) { + if (a.first != VSOMEIP_ROUTING_CLIENT && a.first != host_->get_client()) { + std::shared_ptr<endpoint> its_endpoint + = host_->find_local(a.first); + if (its_endpoint) { + its_endpoint->send(&_command[0], uint32_t(_command.size())); + } + } + } +} + +bool routing_manager_stub::send_subscribe( + const std::shared_ptr<endpoint>& _target, client_t _client, + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const std::shared_ptr<debounce_filter_impl_t> &_filter, + remote_subscription_id_t _id) { + + bool has_sent(false); + + if (_target) { + + protocol::subscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_major(_major); + its_command.set_event(_event); + its_command.set_filter(_filter); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe command serialization failed (" + << std::dec << int(its_error) << ")"; + + } else { + VSOMEIP_WARNING << __func__ + << " Couldn't send subscription to local client [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " subscriber: " << std::setw(4) << _client; + } + + return has_sent; +} + +bool routing_manager_stub::send_unsubscribe( + const std::shared_ptr<endpoint>& _target, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _id) { + + bool has_sent(false); + + if (_target) { + + protocol::unsubscribe_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command serialization failed (" + << std::dec << int(its_error) << ")"; + } else { + VSOMEIP_WARNING << __func__ + << " Couldn't send unsubscription to local client [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " subscriber: "<< std::setw(4) << _client; + } + + return has_sent; +} + +bool routing_manager_stub::send_expired_subscription( + const std::shared_ptr<endpoint>& _target, + client_t _client, service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, + remote_subscription_id_t _id) { + + bool has_sent(false); + + if (_target) { + + protocol::expire_command its_command; + its_command.set_client(_client); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_event(_event); + its_command.set_pending_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + has_sent = _target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": unsubscribe command serialization failed (" + << std::dec << int(its_error) << ")"; + } else { + VSOMEIP_WARNING << __func__ + << " Couldn't send expired subscription to local client [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]" + << " subscriber: "<< std::setw(4) << _client; + } + + return has_sent; +} + +void routing_manager_stub::send_subscribe_ack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + + std::shared_ptr<endpoint> its_target = host_->find_local(_client); + if (its_target) { + + protocol::subscribe_ack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_client); + its_command.set_event(_event); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + (void)its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; + } +} + +void routing_manager_stub::send_subscribe_nack(client_t _client, service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + + std::shared_ptr<endpoint> its_target = host_->find_local(_client); + if (its_target) { + + protocol::subscribe_nack_command its_command; + its_command.set_client(get_client()); + its_command.set_service(_service); + its_command.set_instance(_instance); + its_command.set_eventgroup(_eventgroup); + its_command.set_subscriber(_client); + its_command.set_event(_event); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + (void)its_target->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else + VSOMEIP_ERROR << __func__ + << ": subscribe ack command serialization failed (" + << std::dec << int(its_error) << ")"; + } +} + +bool routing_manager_stub::contained_in_routing_info( + client_t _client, service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + auto found_client = routing_info_.find(_client); + if (found_client != routing_info_.end()) { + auto found_service = found_client->second.second.find(_service); + if (found_service != found_client->second.second.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (found_instance->second.first == _major + && found_instance->second.second == _minor) { + return true; + } + } + } + } + return false; +} + +// Watchdog +void routing_manager_stub::broadcast_ping() const { + + protocol::ping_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + broadcast(its_buffer); + else + VSOMEIP_ERROR << __func__ + << ": ping command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +void routing_manager_stub::on_pong(client_t _client) { + { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + auto found_info = routing_info_.find(_client); + if (found_info != routing_info_.end()) { + found_info->second.first = 0; + } else { + VSOMEIP_ERROR << "Received PONG from unregistered application: " + << std::hex << std::setw(4) << std::setfill('0') << _client; + } + } + remove_from_pinged_clients(_client); + host_->on_pong(_client); +} + +void routing_manager_stub::start_watchdog() { + + auto its_callback = + [this](boost::system::error_code const &_error) { + if (!_error) + check_watchdog(); + }; + { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + // Divide / 2 as start and check sleep each + watchdog_timer_.expires_from_now( + std::chrono::milliseconds( + configuration_->get_watchdog_timeout() / 2)); + + watchdog_timer_.async_wait(its_callback); + } +} + +void routing_manager_stub::check_watchdog() { + { + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + for (auto i = routing_info_.begin(); i != routing_info_.end(); ++i) { + i->second.first++; + } + } + broadcast_ping(); + + + auto its_callback = [this](boost::system::error_code const &_error) { + (void)_error; + std::list< client_t > lost; + { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + for (const auto& i : routing_info_) { + if (i.first > 0 && i.first != host_->get_client()) { + if (i.second.first > configuration_->get_allowed_missing_pongs()) { + VSOMEIP_WARNING << "Lost contact to application " << std::hex << (int)i.first; + lost.push_back(i.first); + } + } + } + } + for (auto i : lost) { + host_->handle_client_error(i); + } + start_watchdog(); + }; + { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + watchdog_timer_.expires_from_now( + std::chrono::milliseconds( + configuration_->get_watchdog_timeout() / 2)); + watchdog_timer_.async_wait(its_callback); + } +} + +void routing_manager_stub::create_local_receiver() { + std::lock_guard<std::mutex> its_lock(local_receiver_mutex_); + + if (local_receiver_) { + return; + } +#ifdef __linux__ + else if (!configuration_->get_policy_manager()->check_credentials(get_client(), host_->get_sec_client())) { + VSOMEIP_ERROR << "vSomeIP Security: Client 0x" << std::hex << get_client() + << " : routing_manager_stub::create_local_receiver: isn't allowed" + << " to create a server endpoint due to credential check failed!"; + return; + } +#endif + local_receiver_ = std::static_pointer_cast<endpoint_manager_base>( + host_->get_endpoint_manager())->create_local_server(shared_from_this()); + + if (local_receiver_) + local_receiver_->start(); +} + +bool routing_manager_stub::send_ping(client_t _client) { + + bool has_sent(false); + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_); + + if (pinged_clients_.find(_client) != pinged_clients_.end()) { + // client was already pinged: don't ping again and wait for answer + // or timeout of previous ping. + has_sent = true; + } else { + boost::system::error_code ec; + pinged_clients_timer_.cancel(ec); + if (ec) { + VSOMEIP_ERROR << "routing_manager_stub::send_ping cancellation of " + "timer failed: " << ec.message(); + } + const std::chrono::steady_clock::time_point now( + std::chrono::steady_clock::now()); + + std::chrono::milliseconds next_timeout(configured_watchdog_timeout_); + for (const auto &tp : pinged_clients_) { + const std::chrono::milliseconds its_clients_timeout = + std::chrono::duration_cast<std::chrono::milliseconds>( + now - tp.second); + if (next_timeout > its_clients_timeout) { + next_timeout = its_clients_timeout; + } + } + + pinged_clients_[_client] = now; + + ec.clear(); + pinged_clients_timer_.expires_from_now(next_timeout, ec); + if (ec) { + VSOMEIP_ERROR << "routing_manager_stub::send_ping setting " + "expiry time of timer failed: " << ec.message(); + } + pinged_clients_timer_.async_wait( + std::bind(&routing_manager_stub::on_ping_timer_expired, this, + std::placeholders::_1)); + + protocol::ping_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + has_sent = its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + else + VSOMEIP_ERROR << __func__ + << ": ping command serialization failed (" + << std::dec << int(its_error) << ")"; + } + } + + return has_sent; +} + +void routing_manager_stub::on_ping_timer_expired( + boost::system::error_code const &_error) { + if(_error) { + return; + } + std::forward_list<client_t> timed_out_clients; + std::chrono::milliseconds next_timeout(configured_watchdog_timeout_); + bool pinged_clients_remaining(false); + + { + // remove timed out clients + std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_); + const std::chrono::steady_clock::time_point now( + std::chrono::steady_clock::now()); + + for (auto client_iter = pinged_clients_.begin(); + client_iter != pinged_clients_.end(); ) { + if ((now - client_iter->second) >= configured_watchdog_timeout_) { + timed_out_clients.push_front(client_iter->first); + client_iter = pinged_clients_.erase(client_iter); + } else { + ++client_iter; + } + } + pinged_clients_remaining = (pinged_clients_.size() > 0); + + if(pinged_clients_remaining) { + // find out next timeout + for (const auto &tp : pinged_clients_) { + const std::chrono::milliseconds its_clients_timeout = + std::chrono::duration_cast<std::chrono::milliseconds>( + now - tp.second); + if (next_timeout > its_clients_timeout) { + next_timeout = its_clients_timeout; + } + } + } + } + + for (const client_t client : timed_out_clients) { + // Client did not respond to ping. Report client_error in order to + // accept pending offers trying to replace the offers of the client + // that seems to be gone. + host_->handle_client_error(client); + } + if (pinged_clients_remaining) { + boost::system::error_code ec; + pinged_clients_timer_.expires_from_now(next_timeout, ec); + if (ec) { + VSOMEIP_ERROR<< "routing_manager_stub::on_ping_timer_expired " + "setting expiry time of timer failed: " << ec.message(); + } + pinged_clients_timer_.async_wait( + std::bind(&routing_manager_stub::on_ping_timer_expired, this, + std::placeholders::_1)); + } +} + +void routing_manager_stub::remove_from_pinged_clients(client_t _client) { + std::lock_guard<std::mutex> its_lock(pinged_clients_mutex_); + if (!pinged_clients_.size()) { + return; + } + boost::system::error_code ec; + pinged_clients_timer_.cancel(ec); + if (ec) { + VSOMEIP_ERROR << "routing_manager_stub::remove_from_pinged_clients " + "cancellation of timer failed: " << ec.message(); + } + pinged_clients_.erase(_client); + + if (!pinged_clients_.size()) { + return; + } + const std::chrono::steady_clock::time_point now( + std::chrono::steady_clock::now()); + std::chrono::milliseconds next_timeout(configured_watchdog_timeout_); + // find out next timeout + for (const auto &tp : pinged_clients_) { + const std::chrono::milliseconds its_clients_timeout = + std::chrono::duration_cast<std::chrono::milliseconds>( + now - tp.second); + if (next_timeout > its_clients_timeout) { + next_timeout = its_clients_timeout; + } + } + ec.clear(); + pinged_clients_timer_.expires_from_now(next_timeout, ec); + if (ec) { + VSOMEIP_ERROR<< "routing_manager_stub::remove_from_pinged_clients " + "setting expiry time of timer failed: " << ec.message(); + } + pinged_clients_timer_.async_wait( + std::bind(&routing_manager_stub::on_ping_timer_expired, this, + std::placeholders::_1)); +} + +bool routing_manager_stub::is_registered(client_t _client) const { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + return (routing_info_.find(_client) != routing_info_.end()); +} + +void routing_manager_stub::update_registration(client_t _client, + registration_type_e _type, + const boost::asio::ip::address &_address, port_t _port) { + + std::stringstream its_client; + its_client << std::hex << std::setfill('0') << std::setw(4) << _client; + + if (_port > 0 && _port < ILLEGAL_PORT) { + its_client << " @ " << _address.to_string() << ":" << std::dec << _port; + } + + VSOMEIP_INFO << "Application/Client " + << its_client.str() + << " is " + << (_type == registration_type_e::REGISTER ? + "registering." : "deregistering."); + + if (_type != registration_type_e::REGISTER) { + configuration_->get_policy_manager()->remove_client_to_sec_client_mapping(_client); + } else { + if (_port > 0 && _port < ILLEGAL_PORT) + host_->add_guest(_client, _address, _port); + } + + if (_type == registration_type_e::DEREGISTER) { + host_->remove_guest(_client); + + // If we receive a DEREGISTER client command + // the endpoint error handler is not longer needed + // as the client is going down anyways. + + // Normally the handler is removed in "remove_local" + // anyways, but as some time takes place until + // the client DEREGISTER command is consumed + // and therefore "remove_local" is finally called + // it was possible the same client registers itself + // again in very short time and then could "overtake" + // the occurring error in the endpoint and was then + // erroneously unregistered even that error has + // nothing to do with the newly registered client. + + auto its_endpoint = host_->find_local(_client); + if (its_endpoint) { + its_endpoint->register_error_handler(nullptr); + } + } + + std::lock_guard<std::mutex> its_lock(client_registration_mutex_); + pending_client_registrations_[_client].push_back(_type); + client_registration_condition_.notify_one(); + + if (_type != registration_type_e::REGISTER) { + std::lock_guard<std::mutex> its_lock(used_client_ids_mutex_); + used_client_ids_.erase(_client); + } +} + +client_t routing_manager_stub::get_client() const { + return host_->get_client(); +} + +void routing_manager_stub::handle_credentials(const client_t _client, std::set<protocol::service> &_requests) { + if (!_requests.size()) { + return; + } + + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + std::set<std::pair<uid_t, gid_t>> its_credentials; + vsomeip_sec_client_t its_requester_sec_client; + if (configuration_->get_policy_manager()->get_client_to_sec_client_mapping(_client, its_requester_sec_client)) { + // determine credentials of offering clients using current routing info + std::set<client_t> its_offering_clients; + + // search in local clients for the offering client + for (auto request : _requests) { + std::set<client_t> its_clients; + its_clients = host_->find_local_clients(request.service_, request.instance_); + for (auto its_client : its_clients) { + its_offering_clients.insert(its_client); + } + } + + // search for UID / GID linked with the client ID that offers the requested services + for (auto its_offering_client : its_offering_clients) { + vsomeip_sec_client_t its_sec_client; + if (configuration_->get_policy_manager()->get_client_to_sec_client_mapping(its_offering_client, its_sec_client)) { + if (its_sec_client.port == VSOMEIP_SEC_PORT_UNUSED + && !utility::compare(its_sec_client, its_requester_sec_client)) { + + its_credentials.insert(std::make_pair( + its_sec_client.user, its_sec_client.group)); + } + } + } + + // send credentials to clients + if (!its_credentials.empty()) + send_client_credentials(_client, its_credentials); + } +} + +void routing_manager_stub::handle_requests(const client_t _client, std::set<protocol::service> &_requests) { + + if (_requests.empty()) + return; + + boost::asio::ip::address its_address; + port_t its_port; + + std::vector<protocol::routing_info_entry> its_entries; + std::lock_guard<std::mutex> its_guard(routing_info_mutex_); + + for (auto request : _requests) { + service_requests_[_client][request.service_][request.instance_] + = std::make_pair(request.major_, request.minor_); + if (request.instance_ == ANY_INSTANCE) { + std::set<client_t> its_clients = host_->find_local_clients(request.service_, request.instance_); + // insert VSOMEIP_ROUTING_CLIENT to check whether service is remotely offered + its_clients.insert(VSOMEIP_ROUTING_CLIENT); + for (const client_t c : its_clients) { + if (c != VSOMEIP_ROUTING_CLIENT && + c != host_->get_client()) { + if (!is_connected(c, _client)) { + add_connection(c, _client); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(_client); + if (host_->get_guest(_client, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + if (_client == c) { + its_entries.emplace_back(its_entry); + } else { + send_client_routing_info(c, its_entry); + } + } + } + if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { + const auto found_client = routing_info_.find(c); + if (found_client != routing_info_.end()) { + const auto found_service = found_client->second.second.find(request.service_); + if (found_service != found_client->second.second.end()) { + for (auto instance : found_service->second) { + add_connection(_client, c); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE); + its_entry.set_client(c); + if (host_->get_guest(c, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ request.service_, instance.first, + instance.second.first, instance.second.second }); + its_entries.emplace_back(its_entry); + } + } + } + } + } + } else { + const client_t c = host_->find_local_client(request.service_, request.instance_); + const auto found_client = routing_info_.find(c); + if (found_client != routing_info_.end()) { + const auto found_service = found_client->second.second.find(request.service_); + if (found_service != found_client->second.second.end()) { + const auto found_instance = found_service->second.find(request.instance_); + if (found_instance != found_service->second.end()) { + if (c != VSOMEIP_ROUTING_CLIENT && c != host_->get_client()) { + if (!is_connected(c, _client)) { + add_connection(c, _client); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_CLIENT); + its_entry.set_client(_client); + if (host_->get_guest(_client, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + if (_client == c) { + its_entries.emplace_back(its_entry); + } else { + send_client_routing_info(c, its_entry); + } + } + } + if (_client != VSOMEIP_ROUTING_CLIENT && _client != host_->get_client()) { + add_connection(_client, c); + + protocol::routing_info_entry its_entry; + its_entry.set_type(protocol::routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE); + its_entry.set_client(c); + if (host_->get_guest(c, its_address, its_port)) { + its_entry.set_address(its_address); + its_entry.set_port(its_port); + } + its_entry.add_service({ request.service_, request.instance_, + found_instance->second.first, found_instance->second.second }); + its_entries.emplace_back(its_entry); + } + } + } + } + } + } + + if (!its_entries.empty()) + send_client_routing_info(_client, std::move(its_entries)); +} + +void routing_manager_stub::on_client_id_timer_expired(boost::system::error_code const &_error) { + std::set<client_t> used_client_ids; + { + std::lock_guard<std::mutex> its_lock(used_client_ids_mutex_); + used_client_ids = used_client_ids_; + used_client_ids_.clear(); + } + + std::set<client_t> erroneous_clients; + if (!_error) { + std::lock_guard<std::mutex> its_lock(routing_info_mutex_); + for (auto client : used_client_ids) { + if (client != VSOMEIP_ROUTING_CLIENT && client != get_client()) { + if (routing_info_.find(client) == routing_info_.end()) { + erroneous_clients.insert(client); + } + } + } + } + for (auto client : erroneous_clients) { + VSOMEIP_WARNING << "Releasing client identifier " + << std::hex << std::setw(4) << std::setfill('0') << client << ". " + << "Its corresponding application went offline while no " + << "routing manager was running."; + host_->handle_client_error(client); + } +} + +void routing_manager_stub::print_endpoint_status() const { + if (local_receiver_) { + local_receiver_->print_status(); + } + if (root_) { + root_->print_status(); + } +} + +bool routing_manager_stub::send_provided_event_resend_request( + client_t _client, pending_remote_offer_id_t _id) { + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + + protocol::resend_provided_events_command its_command; + its_command.set_client(VSOMEIP_ROUTING_CLIENT); + its_command.set_remote_offer_id(_id); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + return its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + } else { + VSOMEIP_WARNING << __func__ << " Couldn't send provided event resend " + "request to local client: 0x" + << std::hex << std::setw(4) << std::setfill('0') << _client; + } + + return false; +} + +#ifndef VSOMEIP_DISABLE_SECURITY +bool routing_manager_stub::is_policy_cached(uid_t _uid) { + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + if (updated_security_policies_.find(_uid) + != updated_security_policies_.end()) { + VSOMEIP_INFO << __func__ << " Policy for UID: " << std::dec + << _uid << " was already updated before!"; + return true; + } else { + return false; + } + } +} + +void routing_manager_stub::policy_cache_add(uid_t _uid, const std::shared_ptr<payload>& _payload) { + // cache security policy payload for later distribution to new registering clients + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + updated_security_policies_[_uid] = _payload; + } +} + +void routing_manager_stub::policy_cache_remove(uid_t _uid) { + { + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + updated_security_policies_.erase(_uid); + } +} + +bool routing_manager_stub::send_update_security_policy_request(client_t _client, pending_security_update_id_t _update_id, + uid_t _uid, const std::shared_ptr<payload>& _payload) { + (void)_uid; + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + std::vector<byte_t> its_command; + // command + its_command.push_back(byte_t(protocol::id_e::UPDATE_SECURITY_POLICY_ID)); + + // version + its_command.push_back(0x00); + its_command.push_back(0x00); + + // client ID + for (uint32_t i = 0; i < sizeof(client_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&_client)[i]); + } + // security update id length + payload length including gid and uid + std::uint32_t its_size = uint32_t(sizeof(pending_security_update_id_t) + _payload->get_length()); + for (uint32_t i = 0; i < sizeof(its_size); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&its_size)[i]); + } + // ID of update request + for (uint32_t i = 0; i < sizeof(pending_security_update_id_t); ++i) { + its_command.push_back( + reinterpret_cast<const byte_t*>(&_update_id)[i]); + } + // payload + for (uint32_t i = 0; i < _payload->get_length(); ++i) { + its_command.push_back(_payload->get_data()[i]); + } + + return its_endpoint->send(its_command.data(), uint32_t(its_command.size())); + } else { + return false; + } +} + +bool routing_manager_stub::send_cached_security_policies(client_t _client) { + + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) { + + + std::lock_guard<std::mutex> its_lock(updated_security_policies_mutex_); + if (!updated_security_policies_.empty()) { + + VSOMEIP_INFO << __func__ << " Distributing [" + << std::dec << updated_security_policies_.size() + << "] security policy updates to registering client: " + << std::hex << _client; + + protocol::distribute_security_policies_command its_command; + its_command.set_client(get_client()); + its_command.set_payloads(updated_security_policies_); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + return its_endpoint->send(its_buffer.data(), uint32_t(its_buffer.size())); + + VSOMEIP_ERROR << __func__ + << ": serializing distribute security policies (" + << static_cast<int>(its_error) + << ")"; + } + } else + VSOMEIP_WARNING << __func__ + << ": could not send cached security policies to registering client: 0x" + << std::hex << std::setw(4) << std::setfill('0') << _client; + + return false; +} + +bool routing_manager_stub::send_remove_security_policy_request( + client_t _client, pending_security_update_id_t _update_id, + uid_t _uid, gid_t _gid) { + + protocol::remove_security_policy_command its_command; + its_command.set_client(_client); + its_command.set_update_id(_update_id); + its_command.set_uid(_uid); + its_command.set_gid(_gid); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(_client); + if (its_endpoint) + return its_endpoint->send(&its_buffer[0], uint32_t(its_buffer.size())); + else + VSOMEIP_ERROR << __func__ + << ": cannot find local client endpoint for client " + << std::hex << std::setw(4) << std::setfill('0') + << _client; + } else + VSOMEIP_ERROR << __func__ + << ": remove security policy command serialization failed (" + << std::dec << static_cast<int>(its_error) + << ")"; + + return false; + +} + +bool +routing_manager_stub::add_requester_policies(uid_t _uid, gid_t _gid, + const std::set<std::shared_ptr<policy> > &_policies) { + + std::lock_guard<std::mutex> its_lock(requester_policies_mutex_); + auto found_uid = requester_policies_.find(_uid); + if (found_uid != requester_policies_.end()) { + auto found_gid = found_uid->second.find(_gid); + if (found_gid != found_uid->second.end()) { + found_gid->second.insert(_policies.begin(), _policies.end()); + } else { + found_uid->second[_gid] = _policies; + } + } else { + requester_policies_[_uid][_gid] = _policies; + } + + // Check whether clients with uid/gid are already registered. + // If yes, update their policy + std::unordered_set<client_t> its_clients; + configuration_->get_policy_manager()->get_clients(_uid, _gid, its_clients); + + if (!its_clients.empty()) + return send_requester_policies(its_clients, _policies); + + return true; +} + +void +routing_manager_stub::remove_requester_policies(uid_t _uid, gid_t _gid) { + + std::lock_guard<std::mutex> its_lock(requester_policies_mutex_); + auto found_uid = requester_policies_.find(_uid); + if (found_uid != requester_policies_.end()) { + found_uid->second.erase(_gid); + if (found_uid->second.empty()) + requester_policies_.erase(_uid); + } +} + +void +routing_manager_stub::get_requester_policies(uid_t _uid, gid_t _gid, + std::set<std::shared_ptr<policy> > &_policies) const { + + std::lock_guard<std::mutex> its_lock(requester_policies_mutex_); + auto found_uid = requester_policies_.find(_uid); + if (found_uid != requester_policies_.end()) { + auto found_gid = found_uid->second.find(_gid); + if (found_gid != found_uid->second.end()) + _policies = found_gid->second; + } +} + +void +routing_manager_stub::add_pending_security_update_handler( + pending_security_update_id_t _id, const security_update_handler_t &_handler) { + + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + security_update_handlers_[_id] = _handler; +} + +void +routing_manager_stub::add_pending_security_update_timer( + pending_security_update_id_t _id) { + + std::shared_ptr<boost::asio::steady_timer> its_timer + = std::make_shared<boost::asio::steady_timer>(io_); + + boost::system::error_code ec; + its_timer->expires_from_now(std::chrono::milliseconds(3000), ec); + if (!ec) { + its_timer->async_wait( + std::bind( + &routing_manager_stub::on_security_update_timeout, + shared_from_this(), + std::placeholders::_1, _id, its_timer)); + } else { + VSOMEIP_ERROR << __func__ + << "[" << std::dec << _id << "]: timer creation: " + << ec.message(); + } + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + security_update_timers_[_id] = its_timer; +} + +bool +routing_manager_stub::send_requester_policies(const std::unordered_set<client_t> &_clients, + const std::set<std::shared_ptr<policy> > &_policies) { + + pending_security_update_id_t its_policy_id; + + // serialize the policies and send them... + for (const auto &p : _policies) { + std::vector<byte_t> its_policy_data; + if (p->serialize(its_policy_data)) { + std::vector<byte_t> its_message; + its_message.push_back(byte_t(protocol::id_e::UPDATE_SECURITY_POLICY_INT_ID)); + + // version + its_message.push_back(0); + its_message.push_back(0); + + // client identifier + its_message.push_back(0); + its_message.push_back(0); + + uint32_t its_policy_size = static_cast<uint32_t>(its_policy_data.size() + sizeof(uint32_t)); + + uint8_t new_its_policy_size[4] = {0}; + bithelper::write_uint32_le(its_policy_size, new_its_policy_size); + its_message.insert(its_message.end(), new_its_policy_size, new_its_policy_size + sizeof(new_its_policy_size)); + + its_policy_id = pending_security_update_add(_clients); + uint8_t new_its_policy_id[4] = {0}; + bithelper::write_uint32_le(its_policy_id, new_its_policy_id); + its_message.insert(its_message.end(), new_its_policy_id, new_its_policy_id + sizeof(new_its_policy_id)); + its_message.insert(its_message.end(), its_policy_data.begin(), its_policy_data.end()); + + for (const auto c : _clients) { + std::shared_ptr<endpoint> its_endpoint = host_->find_local(c); + if (its_endpoint) + its_endpoint->send(&its_message[0], static_cast<uint32_t>(its_message.size())); + } + } + } + + return true; +} + +void routing_manager_stub::on_security_update_timeout( + const boost::system::error_code& _error, + pending_security_update_id_t _id, + std::shared_ptr<boost::asio::steady_timer> _timer) { + (void)_timer; + if (_error) { + // timer was cancelled + return; + } + security_update_state_e its_state = security_update_state_e::SU_UNKNOWN_USER_ID; + std::unordered_set<client_t> its_missing_clients = pending_security_update_get(_id); + { + // erase timer + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + security_update_timers_.erase(_id); + } + { + // print missing responses and check if some clients did not respond because they already disconnected + if (!its_missing_clients.empty()) { + for (auto its_client : its_missing_clients) { + VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client + << " did not respond to the policy update / removal with ID: 0x" << std::hex << _id; + if (!host_->find_local(its_client)) { + VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client + << " is not connected anymore, do not expect answer for policy update / removal with ID: 0x" + << std::hex << _id; + pending_security_update_remove(_id, its_client); + } + } + } + + its_missing_clients = pending_security_update_get(_id); + if (its_missing_clients.empty()) { + VSOMEIP_INFO << __func__ << ": Received all responses for " + "security update/removal ID: 0x" << std::hex << _id; + its_state = security_update_state_e::SU_SUCCESS; + } + { + // erase pending security update + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + pending_security_updates_.erase(_id); + } + + // call handler with error on timeout or with SUCCESS if missing clients are not connected + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + const auto found_handler = security_update_handlers_.find(_id); + if (found_handler != security_update_handlers_.end()) { + found_handler->second(its_state); + security_update_handlers_.erase(found_handler); + } else { + VSOMEIP_WARNING << __func__ << ": Callback not found for security update / removal with ID: 0x" + << std::hex << _id; + } + } +} + +bool routing_manager_stub::update_security_policy_configuration( + uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy, + const std::shared_ptr<payload> &_payload, + const security_update_handler_t &_handler) { + + bool ret(true); + + // cache security policy payload for later distribution to new registering clients + policy_cache_add(_uid, _payload); + + // update security policy from configuration + configuration_->get_policy_manager()->update_security_policy(_uid, _gid, _policy); + + // Build requester policies for the services offered by the new policy + std::set<std::shared_ptr<policy> > its_requesters; + configuration_->get_policy_manager()->get_requester_policies(_policy, its_requesters); + + // and add them to the requester policy cache + add_requester_policies(_uid, _gid, its_requesters); + + // determine currently connected clients + std::unordered_set<client_t> its_clients_to_inform; + auto its_epm = host_->get_endpoint_manager(); + if (its_epm) + its_clients_to_inform = its_epm->get_connected_clients(); + + // add handler + pending_security_update_id_t its_id; + if (!its_clients_to_inform.empty()) { + its_id = pending_security_update_add(its_clients_to_inform); + + add_pending_security_update_handler(its_id, _handler); + add_pending_security_update_timer(its_id); + + // trigger all currently connected clients to update the security policy + uint32_t sent_counter(0); + uint32_t its_tranche = + uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1); + VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size() + << "] currently connected clients about policy update for UID: " + << std::dec << _uid << " with update ID: 0x" << std::hex << its_id; + for (auto its_client : its_clients_to_inform) { + if (!send_update_security_policy_request(its_client, its_id, _uid, _payload)) { + VSOMEIP_INFO << __func__ << ": Couldn't send update security policy " + << std::hex << std::setfill('0') + << "request to client 0x" << std::setw(4) << its_client + << " policy UID: " << std::setw(4) << _uid + << " GID: " << std::setw(4) << _gid + << " with update ID: 0x" << its_id + << " as client already disconnected"; + // remove client from expected answer list + pending_security_update_remove(its_id, its_client); + } + sent_counter++; + // Prevent burst + if (sent_counter % its_tranche == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + } else { + // if routing manager has no client call the handler directly + _handler(security_update_state_e::SU_SUCCESS); + } + + return ret; +} + +bool routing_manager_stub::remove_security_policy_configuration( + uid_t _uid, gid_t _gid, const security_update_handler_t &_handler) { + + bool ret(true); + + // remove security policy from configuration (only if there was a updateACL call before) + if (is_policy_cached(_uid)) { + if (!configuration_->get_policy_manager()->remove_security_policy(_uid, _gid)) { + _handler(security_update_state_e::SU_UNKNOWN_USER_ID); + ret = false; + } else { + // remove policy from cache to prevent sending it to registering clients + policy_cache_remove(_uid); + + // add handler + pending_security_update_id_t its_id; + + // determine currently connected clients + std::unordered_set<client_t> its_clients_to_inform; + auto its_epm = host_->get_endpoint_manager(); + if (its_epm) + its_clients_to_inform = its_epm->get_connected_clients(); + + if (!its_clients_to_inform.empty()) { + its_id = pending_security_update_add(its_clients_to_inform); + + add_pending_security_update_handler(its_id, _handler); + add_pending_security_update_timer(its_id); + + // trigger all clients to remove the security policy + uint32_t sent_counter(0); + uint32_t its_tranche = + uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1); + VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size() + << "] currently connected clients about policy removal for UID: " + << std::dec << _uid << " with update ID: " << its_id; + for (auto its_client : its_clients_to_inform) { + if (!send_remove_security_policy_request(its_client, its_id, _uid, _gid)) { + VSOMEIP_INFO << __func__ << ": Couldn't send remove security policy " + << std::hex << std::setfill('0') + << "request to client 0x" << std::setw(4) << its_client + << " policy UID: " << std::setw(4) << _uid + << " GID: " << std::setw(4) << _gid + << " with update ID: 0x" << its_id + << " as client already disconnected"; + // remove client from expected answer list + pending_security_update_remove(its_id, its_client); + } + sent_counter++; + // Prevent burst + if (sent_counter % its_tranche == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + } else { + // if routing manager has no client call the handler directly + _handler(security_update_state_e::SU_SUCCESS); + } + } + } + else { + _handler(security_update_state_e::SU_UNKNOWN_USER_ID); + ret = false; + } + return ret; +} + +pending_security_update_id_t routing_manager_stub::pending_security_update_add( + const std::unordered_set<client_t>& _clients) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + if (++pending_security_update_id_ == 0) { + pending_security_update_id_++; + } + pending_security_updates_[pending_security_update_id_] = _clients; + + return pending_security_update_id_; +} + +std::unordered_set<client_t> routing_manager_stub::pending_security_update_get( + pending_security_update_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + std::unordered_set<client_t> its_missing_clients; + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + its_missing_clients = pending_security_updates_[_id]; + } + return its_missing_clients; +} + +bool routing_manager_stub::pending_security_update_remove( + pending_security_update_id_t _id, client_t _client) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + if (found_si->second.erase(_client)) { + return true; + } + } + return false; +} + +bool routing_manager_stub::is_pending_security_update_finished( + pending_security_update_id_t _id) { + std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_); + bool ret(false); + auto found_si = pending_security_updates_.find(_id); + if (found_si != pending_security_updates_.end()) { + if (!found_si->second.size()) { + ret = true; + } + } + if (ret) { + pending_security_updates_.erase(_id); + } + return ret; +} + +void routing_manager_stub::on_security_update_response( + pending_security_update_id_t _id, client_t _client) { + if (pending_security_update_remove(_id, _client)) { + if (is_pending_security_update_finished(_id)) { + // cancel timeout timer + { + std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_); + auto found_timer = security_update_timers_.find(_id); + if (found_timer != security_update_timers_.end()) { + boost::system::error_code ec; + found_timer->second->cancel(ec); + security_update_timers_.erase(found_timer); + } else { + VSOMEIP_WARNING << __func__ << ": Received all responses " + "for security update/removal ID: 0x" + << std::hex << _id << " but timeout already happened"; + } + } + + // call handler + { + std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_); + auto found_handler = security_update_handlers_.find(_id); + if (found_handler != security_update_handlers_.end()) { + found_handler->second(security_update_state_e::SU_SUCCESS); + security_update_handlers_.erase(found_handler); + VSOMEIP_INFO << __func__ << ": Received all responses for " + "security update/removal ID: 0x" << std::hex << _id; + } else { + VSOMEIP_WARNING << __func__ << ": Received all responses " + "for security update/removal ID: 0x" + << std::hex << _id << " but didn't find handler"; + } + } + } + } +} +#endif // !VSOMEIP_DISABLE_SECURITY + +void routing_manager_stub::send_suspend() const { + + protocol::suspend_command its_command; + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + + if (its_error == protocol::error_e::ERROR_OK) + broadcast(its_buffer); + else + VSOMEIP_ERROR << __func__ + << ": suspend command serialization failed (" + << std::dec << int(its_error) << ")"; +} + +routing_state_e routing_manager_stub::get_routing_state() { + return host_->get_routing_state(); +} + +void +routing_manager_stub::remove_subscriptions(port_t _local_port, + const boost::asio::ip::address &_remote_address, + port_t _remote_port) { + + (void)_local_port; + (void)_remote_address; + (void)_remote_port; + // dummy method to implement routing_host interface +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/serviceinfo.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/serviceinfo.cpp new file mode 100644 index 00000000000..51afab567d6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/routing/src/serviceinfo.cpp @@ -0,0 +1,139 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/serviceinfo.hpp" + +namespace vsomeip_v3 { + +serviceinfo::serviceinfo(service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, bool _is_local) : + service_(_service), + instance_(_instance), major_(_major), minor_(_minor), ttl_(0), reliable_(nullptr), + unreliable_(nullptr), is_local_(_is_local), is_in_mainphase_(false), + accepting_remote_subscription_(false) { + + std::chrono::seconds ttl = static_cast<std::chrono::seconds> (_ttl); + ttl_ = std::chrono::duration_cast<std::chrono::milliseconds>(ttl); +} + +serviceinfo::serviceinfo(const serviceinfo& _other) : + service_(_other.service_), + instance_(_other.instance_), + major_(_other.major_), + minor_(_other.minor_), + ttl_(_other.ttl_), + reliable_(_other.reliable_), + unreliable_(_other.unreliable_), + requesters_(_other.requesters_), + is_local_(_other.is_local_.load()), + is_in_mainphase_(_other.is_in_mainphase_.load()) + {} + +serviceinfo::~serviceinfo() { +} + +service_t serviceinfo::get_service() const { + return service_; +} + +instance_t serviceinfo::get_instance() const { + return instance_; +} + +major_version_t serviceinfo::get_major() const { + return major_; +} + +minor_version_t serviceinfo::get_minor() const { + return minor_; +} + +ttl_t serviceinfo::get_ttl() const { + std::lock_guard<std::mutex> its_lock(ttl_mutex_); + ttl_t ttl = static_cast<ttl_t>(std::chrono::duration_cast<std::chrono::seconds>(ttl_).count()); + return ttl; +} + +void serviceinfo::set_ttl(ttl_t _ttl) { + std::lock_guard<std::mutex> its_lock(ttl_mutex_); + std::chrono::seconds ttl = static_cast<std::chrono::seconds>(_ttl); + ttl_ = std::chrono::duration_cast<std::chrono::milliseconds> (ttl); +} + +std::chrono::milliseconds serviceinfo::get_precise_ttl() const { + std::lock_guard<std::mutex> its_lock(ttl_mutex_); + return ttl_; +} + +void serviceinfo::set_precise_ttl(std::chrono::milliseconds _precise_ttl) { + std::lock_guard<std::mutex> its_lock(ttl_mutex_); + ttl_ = _precise_ttl; +} + +std::shared_ptr<endpoint> serviceinfo::get_endpoint(bool _reliable) const { + std::lock_guard<std::mutex> its_lock(endpoint_mutex_); + return _reliable ? reliable_ : unreliable_; +} + +void serviceinfo::set_endpoint(const std::shared_ptr<endpoint>& _endpoint, + bool _reliable) { + std::lock_guard<std::mutex> its_lock(endpoint_mutex_); + if (_reliable) { + reliable_ = _endpoint; + } else { + unreliable_ = _endpoint; + } +} + +void serviceinfo::add_client(client_t _client) { + std::lock_guard<std::mutex> its_lock(requesters_mutex_); + requesters_.insert(_client); +} + +void serviceinfo::remove_client(client_t _client) { + std::lock_guard<std::mutex> its_lock(requesters_mutex_); + requesters_.erase(_client); +} + +uint32_t serviceinfo::get_requesters_size() { + std::lock_guard<std::mutex> its_lock(requesters_mutex_); + return static_cast<std::uint32_t>(requesters_.size()); +} + +bool serviceinfo::is_local() const { + return is_local_; +} + +bool serviceinfo::is_in_mainphase() const { + return is_in_mainphase_; +} + +void serviceinfo::set_is_in_mainphase(bool _in_mainphase) { + is_in_mainphase_ = _in_mainphase; +} + +bool serviceinfo::is_accepting_remote_subscriptions() const { + return accepting_remote_subscription_; +} + +void serviceinfo::set_accepting_remote_subscriptions(bool _accepting_remote_subscriptions) { + accepting_remote_subscription_ = _accepting_remote_subscriptions; + if (!_accepting_remote_subscriptions) { + std::lock_guard its_lock(accepting_remote_mutex); + accepting_remote_subscription_from_.clear(); + } +} + +void serviceinfo::add_remote_ip(std::string _remote_ip) { + std::lock_guard its_lock(accepting_remote_mutex); + accepting_remote_subscription_from_.insert(_remote_ip); +} + +std::set<std::string, std::less<>> serviceinfo::get_remote_ip_accepting_sub() { + std::lock_guard its_lock(accepting_remote_mutex); + return accepting_remote_subscription_from_; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/application_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/application_impl.hpp new file mode 100644 index 00000000000..082c21471aa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/application_impl.hpp @@ -0,0 +1,532 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_APPLICATION_IMPL_HPP_ +#define VSOMEIP_V3_APPLICATION_IMPL_HPP_ + +#include <atomic> +#include <condition_variable> +#include <cstdint> +#include <deque> +#include <future> +#include <map> +#include <mutex> +#include <set> +#include <string> +#include <thread> +#include <unordered_map> +#include <vector> + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <windows.h> +#include <processthreadsapi.h> +#endif + +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/export.hpp> +#include <vsomeip/application.hpp> + +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID +#include "../../routing/include/routing_manager_host.hpp" + +namespace vsomeip_v3 { + +class runtime; +class configuration; +class routing_manager; +class routing_manager_stub; + +class application_impl: public application, + public routing_manager_host, + public std::enable_shared_from_this<application_impl> { +public: + VSOMEIP_EXPORT application_impl(const std::string &_name, + const std::string &_path); + VSOMEIP_EXPORT ~application_impl(); + + VSOMEIP_EXPORT bool init(); + VSOMEIP_EXPORT void start(); + VSOMEIP_EXPORT void stop(); + VSOMEIP_EXPORT void process(int _number); + + VSOMEIP_EXPORT security_mode_e get_security_mode() const; + + // Provide services / events + VSOMEIP_EXPORT void offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + VSOMEIP_EXPORT void stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + VSOMEIP_EXPORT void offer_event(service_t _service, instance_t _instance, + event_t _notifier, + const std::set<eventgroup_t> &_eventgroups, event_type_e _type, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + const epsilon_change_func_t &_epsilon_change_func, + reliability_type_e _reliability); + + VSOMEIP_EXPORT void stop_offer_event(service_t _service, + instance_t _instance, event_t _event); + + // Consume services / events + VSOMEIP_EXPORT void request_service( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + VSOMEIP_EXPORT void release_service( + service_t _service, instance_t _instance); + + VSOMEIP_EXPORT void request_event(service_t _service, + instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, + event_type_e _type, reliability_type_e _reliability); + VSOMEIP_EXPORT void release_event(service_t _service, + instance_t _instance, event_t _event); + + VSOMEIP_EXPORT void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, event_t _event); + VSOMEIP_EXPORT void subscribe_with_debounce(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const debounce_filter_t &_filter); + + VSOMEIP_EXPORT void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup); + VSOMEIP_EXPORT void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + VSOMEIP_EXPORT bool is_available(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + VSOMEIP_EXPORT void send(std::shared_ptr<message> _message); + + VSOMEIP_EXPORT void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force) const; + + VSOMEIP_EXPORT void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, client_t _client, + bool _force) const; + + VSOMEIP_EXPORT void register_state_handler(const state_handler_t &_handler); + VSOMEIP_EXPORT void unregister_state_handler(); + + VSOMEIP_EXPORT void register_message_handler(service_t _service, + instance_t _instance, method_t _method, const message_handler_t &_handler); + VSOMEIP_EXPORT void unregister_message_handler(service_t _service, + instance_t _instance, method_t _method); + + VSOMEIP_EXPORT void register_availability_handler(service_t _service, + instance_t _instance, const availability_handler_t &_handler, + major_version_t _major, minor_version_t _minor); + VSOMEIP_EXPORT void register_availability_handler(service_t _service, + instance_t _instance, const availability_state_handler_t &_handler, + major_version_t _major, minor_version_t _minor); + VSOMEIP_EXPORT void unregister_availability_handler(service_t _service, + instance_t _instance, + major_version_t _major, minor_version_t _minor); + + VSOMEIP_EXPORT void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, const subscription_handler_t &_handler); + VSOMEIP_EXPORT void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, const subscription_handler_ext_t &_handler); + VSOMEIP_EXPORT void unregister_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup); + + VSOMEIP_EXPORT bool is_routing() const; + + // routing_manager_host + VSOMEIP_EXPORT const std::string & get_name() const; + VSOMEIP_EXPORT client_t get_client() const; + VSOMEIP_EXPORT void set_client(const client_t &_client); + VSOMEIP_EXPORT session_t get_session(bool _is_request); + VSOMEIP_EXPORT const vsomeip_sec_client_t *get_sec_client() const; + VSOMEIP_EXPORT void set_sec_client_port(port_t _port); + VSOMEIP_EXPORT diagnosis_t get_diagnosis() const; + VSOMEIP_EXPORT std::shared_ptr<configuration> get_configuration() const; + VSOMEIP_EXPORT std::shared_ptr<policy_manager> get_policy_manager() const; + VSOMEIP_EXPORT std::shared_ptr<configuration_public> get_public_configuration() const; + VSOMEIP_EXPORT boost::asio::io_context &get_io(); + + VSOMEIP_EXPORT void on_state(state_type_e _state); + VSOMEIP_EXPORT void on_availability(service_t _service, instance_t _instance, + availability_state_e _state, major_version_t _major, minor_version_t _minor); + VSOMEIP_EXPORT void on_message(std::shared_ptr<message> &&_message); + VSOMEIP_EXPORT void on_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client, const vsomeip_sec_client_t *_sec_client, + const std::string &_env, bool _subscribed, const std::function<void(bool)> &_accepted_cb); + VSOMEIP_EXPORT void on_subscription_status(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error); + VSOMEIP_EXPORT void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective); + VSOMEIP_EXPORT void unregister_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event); + + // service_discovery_host + VSOMEIP_EXPORT routing_manager * get_routing_manager() const; + + VSOMEIP_EXPORT bool are_available(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + VSOMEIP_EXPORT void set_routing_state(routing_state_e _routing_state); + + VSOMEIP_EXPORT void clear_all_handler(); + + + VSOMEIP_EXPORT void get_offered_services_async(offer_type_e _offer_type, const offered_services_handler_t &_handler); + + VSOMEIP_EXPORT void on_offered_services_info(std::vector<std::pair<service_t, instance_t>> &_services); + + VSOMEIP_EXPORT void set_watchdog_handler(const watchdog_handler_t &_handler, std::chrono::seconds _interval); + + VSOMEIP_EXPORT void register_async_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, const async_subscription_handler_t &_handler); + + VSOMEIP_EXPORT void register_async_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, const async_subscription_handler_ext_t &_handler); + + VSOMEIP_EXPORT void set_sd_acceptance_required(const remote_info_t& _remote, + const std::string& _path, bool _enable); + VSOMEIP_EXPORT void set_sd_acceptance_required( + const sd_acceptance_map_type_t& _remotes, bool _enable); + + VSOMEIP_EXPORT sd_acceptance_map_type_t get_sd_acceptance_required(); + + VSOMEIP_EXPORT void register_sd_acceptance_handler(const sd_acceptance_handler_t &_handler); + + VSOMEIP_EXPORT void register_reboot_notification_handler(const reboot_notification_handler_t &_handler); + + VSOMEIP_EXPORT void register_routing_ready_handler(const routing_ready_handler_t &_handler); + VSOMEIP_EXPORT void register_routing_state_handler(const routing_state_handler_t &_handler); + + VSOMEIP_EXPORT bool update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer); + + VSOMEIP_EXPORT void update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + const security_update_handler_t &_handler); + VSOMEIP_EXPORT void remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + const security_update_handler_t &_handler); + + VSOMEIP_EXPORT void register_message_acceptance_handler(const message_acceptance_handler_t &_handler); + + VSOMEIP_EXPORT std::map<std::string, std::string> + get_additional_data(const std::string &_plugin_name); + + VSOMEIP_EXPORT void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_sec_t &_handler); + VSOMEIP_EXPORT void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_sec_t _handler); + + VSOMEIP_EXPORT void register_message_handler_ext( + service_t _service, instance_t _instance, method_t _method, + const message_handler_t &_handler, + handler_registration_type_e _type); + +private: + + using members_key_t = std::uint64_t; + using members_t = std::unordered_map<members_key_t, std::deque<message_handler_t>>; + + static members_key_t to_members_key(service_t _service, instance_t _instance, method_t _method) { + return (static_cast<members_key_t>(_service) << 0) | + (static_cast<members_key_t>(_instance) << 16) | + (static_cast<members_key_t>(_method) << 32); + } + + // + // Types + // + enum class handler_type_e : uint8_t { + MESSAGE, + AVAILABILITY, + STATE, + SUBSCRIPTION, + OFFERED_SERVICES_INFO, + WATCHDOG, + UNKNOWN + }; + + struct sync_handler { + + sync_handler(const std::function<void()> &_handler) : + handler_(_handler), + service_id_(ANY_SERVICE), + instance_id_(ANY_INSTANCE), + method_id_(ANY_METHOD), + session_id_(0), + eventgroup_id_(0), + handler_type_(handler_type_e::UNKNOWN) { } + + sync_handler(service_t _service_id, instance_t _instance_id, + method_t _method_id, session_t _session_id, + eventgroup_t _eventgroup_id, handler_type_e _handler_type) : + handler_(nullptr), + service_id_(_service_id), + instance_id_(_instance_id), + method_id_(_method_id), + session_id_(_session_id), + eventgroup_id_(_eventgroup_id), + handler_type_(_handler_type) { } + + std::function<void()> handler_; + service_t service_id_; + instance_t instance_id_; + method_t method_id_; + session_t session_id_; + eventgroup_t eventgroup_id_; + handler_type_e handler_type_; + }; + + // + // Methods + // + availability_state_e is_available_unlocked(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + availability_state_e are_available_unlocked(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + + void register_availability_handler_unlocked(service_t _service, + instance_t _instance, const availability_state_handler_t &_handler, + major_version_t _major, minor_version_t _minor); + + void main_dispatch(); + void dispatch(); + void invoke_handler(std::shared_ptr<sync_handler> &_handler); + std::shared_ptr<sync_handler> get_next_handler(); + void reschedule_availability_handler(const std::shared_ptr<sync_handler> &_handler); + bool has_active_dispatcher(); + bool is_active_dispatcher(const std::thread::id &_id) const; + void remove_elapsed_dispatchers(); + + void shutdown(); + + void send_back_cached_event(service_t _service, instance_t _instance, event_t _event); + void send_back_cached_eventgroup(service_t _service, instance_t _instance, eventgroup_t _eventgroup); + void check_send_back_cached_event(service_t _service, instance_t _instance, + event_t _event, eventgroup_t _eventgroup, + bool *_send_back_cached_event, + bool *_send_back_cached_eventgroup); + void remove_subscription(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + bool check_for_active_subscription(service_t _service, instance_t _instance, + event_t _event); + + void deliver_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error); + + bool check_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event); + + void print_blocking_call(const std::shared_ptr<sync_handler>& _handler); + + void watchdog_cbk(boost::system::error_code const &_error); + + bool is_local_endpoint(const boost::asio::ip::address &_unicast, port_t _port); + + const std::deque<message_handler_t>& find_handlers(service_t _service, instance_t _instance, method_t _method) const; + + void invoke_availability_handler(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor); + + void increment_active_threads(); + void decrement_active_threads(); + std::uint16_t get_active_threads() const; + + using availability_state_t = std::map<service_t, std::map<instance_t, + std::map<major_version_t, std::map<minor_version_t, availability_state_e>>>>; + + availability_state_e get_availability_state(const availability_state_t& _availability_state, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const; + void set_availability_state(availability_state_t& _availability_state, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, availability_state_e _state) const; + + // + // Attributes + // + std::shared_ptr<runtime> runtime_; + std::atomic<client_t> client_; // unique application identifier + session_t session_; + std::mutex session_mutex_; + + std::mutex initialize_mutex_; + bool is_initialized_; + + std::string name_; + + std::string path_; + std::shared_ptr<configuration> configuration_; + + boost::asio::io_context io_; + std::set<std::shared_ptr<std::thread> > io_threads_; + std::shared_ptr<boost::asio::executor_work_guard< + boost::asio::io_context::executor_type> > work_; + + // Proxy to or the Routing Manager itself + std::shared_ptr<routing_manager> routing_; + + // vsomeip state (registered / deregistered) + state_type_e state_; + + // vsomeip state handler + std::mutex state_handler_mutex_; + state_handler_t handler_; + + // vsomeip security mode + security_mode_e security_mode_; + + // vsomeip offered services handler + std::mutex offered_services_handler_mutex_; + offered_services_handler_t offered_services_handler_; + + // Method/Event (=Member) handlers + members_t members_; + mutable std::mutex members_mutex_; + + // Availability handlers + using stateful_availability_t = std::pair<availability_state_handler_t, availability_state_t>; + using availability_major_minor_t = + std::map<major_version_t, std::map<minor_version_t, stateful_availability_t>>; + std::map<service_t, std::map<instance_t, availability_major_minor_t>> availability_; + mutable std::mutex availability_mutex_; + + // Availability + typedef std::map<instance_t, + std::map<major_version_t, + std::pair<minor_version_t, availability_state_e> + > + > available_instance_t; + typedef std::map<service_t, available_instance_t> available_ext_t; + mutable available_ext_t available_; + + // Subscription handlers + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::pair<subscription_handler_sec_t, + async_subscription_handler_sec_t> > > > subscription_; + mutable std::mutex subscription_mutex_; + std::map<service_t, + std::map<instance_t, std::map<eventgroup_t, + std::map<client_t, error_handler_t > > > > eventgroup_error_handlers_; + mutable std::mutex subscription_error_mutex_; + +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + // Signals + boost::asio::signal_set signals_; + bool catched_signal_; +#endif + + // Handlers + mutable std::deque<std::shared_ptr<sync_handler>> handlers_; + mutable std::mutex handlers_mutex_; + + // Dispatching + std::atomic<bool> is_dispatching_; + // Dispatcher threads + std::map<std::thread::id, std::shared_ptr<std::thread>> dispatchers_; + // Dispatcher threads that elapsed and can be removed + std::set<std::thread::id> elapsed_dispatchers_; + // Dispatcher threads that are running + std::set<std::thread::id> running_dispatchers_; + // Mutex to protect access to dispatchers_ & elapsed_dispatchers_ + mutable std::mutex dispatcher_mutex_; + + // Map of promises/futures to check status of dispatcher threads +#ifdef _WIN32 + std::map<std::thread::id, std::tuple<HANDLE, std::future<void>>> dispatchers_control_; +#else + std::map<std::thread::id, std::tuple<pthread_t, std::future<void>>> dispatchers_control_; +#endif + + // Condition to wakeup the dispatcher thread + mutable std::condition_variable dispatcher_condition_; + std::size_t max_dispatchers_; + std::size_t max_dispatch_time_; + + // Counter for dispatcher threads + std::atomic<uint16_t> dispatcher_counter_; + + std::size_t max_detached_thread_wait_time; + + std::condition_variable stop_cv_; + std::mutex start_stop_mutex_; + bool stopped_; + std::thread stop_thread_; + + std::condition_variable block_stop_cv_; + std::mutex block_stop_mutex_; + std::atomic_bool block_stopping_; + + static uint32_t app_counter__; + static std::mutex app_counter_mutex__; + + bool is_routing_manager_host_; + + // Event subscriptions + std::mutex subscriptions_mutex_; + std::map<service_t, std::map<instance_t, + std::map<event_t, std::map<eventgroup_t, bool>>>> subscriptions_; + + std::thread::id stop_caller_id_; + std::thread::id start_caller_id_; + + bool stopped_called_; + + std::map<service_t, std::map<instance_t, std::map<eventgroup_t, + std::map<event_t, std::pair<subscription_status_handler_t, bool> > > > > subscription_status_handlers_; + std::mutex subscription_status_handlers_mutex_; + + std::mutex subscriptions_state_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::map<event_t, subscription_state_e> + > + > + > subscriptions_state_; + + std::mutex watchdog_timer_mutex_; + boost::asio::steady_timer watchdog_timer_; + watchdog_handler_t watchdog_handler_; + std::chrono::seconds watchdog_interval_; + + bool client_side_logging_; + std::set<std::tuple<service_t, instance_t> > client_side_logging_filter_; + + std::map<std::pair<service_t, instance_t>, + std::deque<std::shared_ptr<sync_handler> > > availability_handlers_; + + vsomeip_sec_client_t sec_client_; + + bool has_session_handling_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_APPLICATION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/runtime_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/runtime_impl.hpp new file mode 100644 index 00000000000..2c4ed5b52a0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/include/runtime_impl.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_RUNTIME_IMPL_HPP_ +#define VSOMEIP_V3_RUNTIME_IMPL_HPP_ + +#include <vsomeip/runtime.hpp> +#include <map> +#include <mutex> + +namespace vsomeip_v3 { + +class runtime_impl: public runtime { +public: + + static std::string get_property(const std::string &_name); + static void set_property(const std::string &_name, const std::string &_value); + + static std::shared_ptr<runtime> get(); + + virtual ~runtime_impl() = default; + + std::shared_ptr<application> create_application( + const std::string &_name); + std::shared_ptr<application> create_application( + const std::string &_name, const std::string &_path); + + std::shared_ptr<message> create_message(bool _reliable) const; + std::shared_ptr<message> create_request(bool _reliable) const; + std::shared_ptr<message> create_response( + const std::shared_ptr<message> &_request) const; + std::shared_ptr<message> create_notification(bool _reliable) const; + + std::shared_ptr<payload> create_payload() const; + std::shared_ptr<payload> create_payload(const byte_t *_data, + uint32_t _size) const; + std::shared_ptr<payload> create_payload( + const std::vector<byte_t> &_data) const; + + std::shared_ptr<application> get_application( + const std::string &_name) const; + + void remove_application( const std::string &_name); + +private: + static std::map<std::string, std::string> properties_; + + std::map<std::string, std::weak_ptr<application>> applications_; + + mutable std::mutex applications_mutex_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_RUNTIME_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/application_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/application_impl.cpp new file mode 100644 index 00000000000..e632770aba9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/application_impl.cpp @@ -0,0 +1,3125 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <future> +#include <thread> +#include <iomanip> +#include <iostream> + +#include <boost/asio/ip/host_name.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/exception/diagnostic_information.hpp> + +#if defined(__linux__) || defined(ANDROID) +#include <dlfcn.h> +#include <sys/syscall.h> +#endif + +#include <vsomeip/defines.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/plugins/pre_configuration_plugin.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/application_impl.hpp" +#ifdef VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS +#include "../../configuration/include/configuration_impl.hpp" +#else +#include "../../configuration/include/configuration.hpp" +#include "../../configuration/include/configuration_plugin.hpp" +#endif // VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS +#include "../../endpoints/include/endpoint.hpp" +#include "../../message/include/serializer.hpp" +#include "../../plugin/include/plugin_manager_impl.hpp" +#include "../../routing/include/routing_manager_impl.hpp" +#include "../../routing/include/routing_manager_client.hpp" +#include "../../security/include/security.hpp" +#include "../../tracing/include/connector_impl.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +#ifdef ANDROID +configuration::~configuration() {} +#endif + +uint32_t application_impl::app_counter__ = 0; +std::mutex application_impl::app_counter_mutex__; + +application_impl::application_impl(const std::string& _name, const std::string& _path) : + runtime_(runtime::get()), client_(VSOMEIP_CLIENT_UNSET), session_(0), is_initialized_(false), + name_(_name), path_(_path), + work_(std::make_shared< + boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>( + io_.get_executor())), + routing_(nullptr), state_(state_type_e::ST_DEREGISTERED), + security_mode_(security_mode_e::SM_ON), +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + signals_(io_, SIGINT, SIGTERM), catched_signal_(false), +#endif + is_dispatching_(false), max_dispatchers_(VSOMEIP_MAX_DISPATCHERS), + max_dispatch_time_(VSOMEIP_MAX_DISPATCH_TIME), dispatcher_counter_(0), + max_detached_thread_wait_time(VSOMEIP_MAX_WAIT_TIME_DETACHED_THREADS), stopped_(false), + block_stopping_(false), is_routing_manager_host_(false), stopped_called_(false), + watchdog_timer_(io_), client_side_logging_(false), has_session_handling_(true) { +} + +application_impl::~application_impl() { + runtime_->remove_application(name_); + +#ifndef VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS + if(configuration_) { + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_configuration_plugin + = std::dynamic_pointer_cast<configuration_plugin>(its_plugin); + if (its_configuration_plugin) { + bool its_removed = its_configuration_plugin->remove_configuration(name_); + if (!its_removed) { + VSOMEIP_WARNING << __func__ <<": Unable to remove configuration entry stored for " << name_; + } + } + } + } +#endif + try { + if (stop_thread_.joinable()) { + stop_thread_.detach(); + } + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (shutdown): " << e.what() << std::endl; + } + + try { + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); + for (const auto& t : io_threads_) { + if (t->joinable()) { + t->detach(); + } + } + io_threads_.clear(); + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (io threads): " << e.what() << std::endl; + } + + try { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (const auto& its_dispatcher : dispatchers_) { + if (its_dispatcher.second->joinable()) { + its_dispatcher.second->detach(); + } + } + dispatchers_.clear(); + } catch (const std::exception& e) { + std::cerr << __func__ << " catched exception (dispatchers): " << e.what() << std::endl; + } +} + +bool application_impl::init() { + std::lock_guard<std::mutex> its_initialized_lock(initialize_mutex_); + if(is_initialized_) { + VSOMEIP_WARNING << "Trying to initialize an already initialized application."; + return true; + } + + // Application name + if (name_ == "") { + const char *its_name = getenv(VSOMEIP_ENV_APPLICATION_NAME); + if (nullptr != its_name) { + name_ = its_name; + } + } + + std::string configuration_path; + + // load configuration from module + std::string config_module = ""; + const char *its_config_module = getenv(VSOMEIP_ENV_CONFIGURATION_MODULE); + if (nullptr != its_config_module) { + // TODO: Add loading of custom configuration module + } else { // load default module +#ifndef VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS + auto its_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_configuration_plugin + = std::dynamic_pointer_cast<configuration_plugin>(its_plugin); + if (its_configuration_plugin) { + configuration_ = its_configuration_plugin->get_configuration(name_, path_); + VSOMEIP_INFO << "Configuration module loaded."; + } else { + std::cerr << "Invalid configuration module!" << std::endl; + std::exit(EXIT_FAILURE); + } + } else { + std::cerr << "1 Configuration module could not be loaded!" << std::endl; + std::exit(EXIT_FAILURE); + } +#else + configuration_ = std::dynamic_pointer_cast<configuration>( + std::make_shared<vsomeip_v3::cfg::configuration_impl>(configuration_path)); + if (configuration_path.length()) { + configuration_->set_configuration_path(configuration_path); + } + configuration_->load(name_); +#endif // VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS + } + + if (configuration_->is_local_routing()) { + sec_client_.port = VSOMEIP_SEC_PORT_UNUSED; +#ifdef __unix__ + sec_client_.user = getuid(); + sec_client_.group = getgid(); +#else + sec_client_.user = ANY_UID; + sec_client_.group = ANY_GID; +#endif + } else { + auto its_guest_address = configuration_->get_routing_guest_address(); + if (its_guest_address.is_v4()) { + sec_client_.host = htonl(its_guest_address.to_v4().to_uint()); + } + sec_client_.port = VSOMEIP_SEC_PORT_UNSET; + } + + // Set security mode + if (configuration_->is_security_enabled()) { + if (configuration_->is_security_external()) { + if (configuration_->get_security()->load()) { + VSOMEIP_INFO << "Using external security implementation!"; + auto its_result = configuration_->get_security()->initialize(); + if (VSOMEIP_SEC_POLICY_OK != its_result) + VSOMEIP_ERROR << "Intializing external security implementation failed (" + << std::dec << its_result << ')'; + } + } else { + VSOMEIP_INFO << "Using internal security implementation!"; + if (configuration_->is_security_audit()) + security_mode_ = security_mode_e::SM_AUDIT; + } + } else { + security_mode_ = security_mode_e::SM_OFF; + VSOMEIP_INFO << "Security disabled!"; + } + + const char *client_side_logging = getenv(VSOMEIP_ENV_CLIENTSIDELOGGING); + if (client_side_logging != nullptr) { + client_side_logging_ = true; + VSOMEIP_INFO << "Client side logging for application: " << name_ + << " is enabled"; + + if ('\0' != *client_side_logging) { + std::stringstream its_converter(client_side_logging); + if ('"' == its_converter.peek()) { + its_converter.get(); // skip quote + } + uint16_t val(0xffffu); + bool stop_parsing(false); + do { + const uint16_t prev_val(val); + its_converter >> std::hex >> std::setw(4) >> val; + const std::stringstream::int_type c = its_converter.eof()?'\0':its_converter.get(); + switch (c) { + case '"': + case '.': + case ':': + case ' ': + case '\0': { + if ('.' != c) { + if (0xffffu == prev_val) { + VSOMEIP_INFO << "+filter " + << std::hex << std::setfill('0') + << std::setw(4) << val; + client_side_logging_filter_.insert(std::make_tuple(val, ANY_INSTANCE)); + } else { + VSOMEIP_INFO << "+filter " + << std::hex << std::setfill('0') + << std::setw(4) << prev_val << "." << std::setw(4) << val; + client_side_logging_filter_.insert(std::make_tuple(prev_val, val)); + } + val = 0xffffu; + } + } + break; + default: + stop_parsing = true; + break; + } + } + while (!stop_parsing && its_converter.good()); + } + } + + std::shared_ptr<configuration> its_configuration = get_configuration(); + if (its_configuration) { + VSOMEIP_INFO << "Initializing vsomeip (" VSOMEIP_VERSION ") application \"" << name_ << "\"."; + client_ = its_configuration->get_id(name_); + + // Max dispatchers is the configured maximum number of dispatchers and + // the main dispatcher + max_dispatchers_ = its_configuration->get_max_dispatchers(name_) + 1; + max_dispatch_time_ = its_configuration->get_max_dispatch_time(name_); + max_detached_thread_wait_time = its_configuration->get_max_detached_thread_wait_time(name_); + + has_session_handling_ = its_configuration->has_session_handling(name_); + if (!has_session_handling_) + VSOMEIP_INFO << "application: " << name_ + << " has session handling switched off!"; + + std::string its_routing_host = its_configuration->get_routing_host_name(); + if (its_routing_host != "") { + is_routing_manager_host_ = (its_routing_host == name_); + if (is_routing_manager_host_ && + !utility::is_routing_manager(configuration_->get_network())) { +#ifndef VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS + VSOMEIP_ERROR << "application: " << name_ << " configured as " + "routing but other routing manager present. Won't " + "instantiate routing"; + is_routing_manager_host_ = false; + return false; +#else + is_routing_manager_host_ = true; +#endif // VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS + } + } else { + auto its_routing_address = its_configuration->get_routing_host_address(); + auto its_routing_port = its_configuration->get_routing_host_port(); + if (its_routing_address.is_unspecified() + || is_local_endpoint(its_routing_address, its_routing_port)) + is_routing_manager_host_ = utility::is_routing_manager(configuration_->get_network()); + } + + if (is_routing_manager_host_) { + VSOMEIP_INFO << "Instantiating routing manager [Host]."; + if (client_ == VSOMEIP_CLIENT_UNSET) { + client_ = static_cast<client_t>( + (configuration_->get_diagnosis_address() << 8) + & configuration_->get_diagnosis_mask()); + utility::request_client_id(configuration_, name_, client_); + } + routing_ = std::make_shared<routing_manager_impl>(this); + } else { + VSOMEIP_INFO << "Instantiating routing manager [Proxy]."; + routing_ = std::make_shared<routing_manager_client>(this, client_side_logging_, client_side_logging_filter_); + } + + routing_->init(); + +#ifdef USE_DLT + // Tracing + std::shared_ptr<trace::connector_impl> its_connector + = trace::connector_impl::get(); + std::shared_ptr<cfg::trace> its_trace_configuration + = its_configuration->get_trace(); + its_connector->configure(its_trace_configuration); +#endif + + VSOMEIP_INFO << "Application(" << (name_ != "" ? name_ : "unnamed") + << ", " << std::hex << std::setfill('0') << std::setw(4) << client_ + << ") is initialized (" + << std::dec << max_dispatchers_ << ", " << max_dispatch_time_ << ")."; + + is_initialized_ = true; + } + +#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING + if (is_initialized_) { + signals_.add(SIGINT); + signals_.add(SIGTERM); + + // Register signal handler + auto its_signal_handler = + [this] (boost::system::error_code const &_error, int _signal) { + if (!_error) { + switch (_signal) { + case SIGTERM: + case SIGINT: + catched_signal_ = true; + stop(); + break; + default: + break; + } + } + }; + signals_.async_wait(its_signal_handler); + } +#endif + + if (configuration_) { + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + for (auto its_library : its_app_plugin_info->second) { + auto its_application_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::APPLICATION_PLUGIN, its_library); + if (its_application_plugin) { + VSOMEIP_INFO << "Client 0x" << std::hex << get_client() + << " Loading plug-in library: " << its_library << " succeeded!"; + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_INITIALIZED); + } + } + } + } else { + std::cerr << "Configuration module could not be loaded!" << std::endl; + std::exit(EXIT_FAILURE); + } + + return is_initialized_; +} + +void application_impl::start() { +#if defined(__linux__) || defined(ANDROID) + if (getpid() != static_cast<pid_t>(syscall(SYS_gettid))) { + // only set threadname if calling thread isn't the main thread + std::stringstream s; + s << std::hex << std::setfill('0') + << std::setw(4) << client_ << "_io" << std::setw(2) << 0; + pthread_setname_np(pthread_self(),s.str().c_str()); + } +#endif + { + std::lock_guard<std::mutex> its_initialized_lock(initialize_mutex_); + if (!is_initialized_) { + VSOMEIP_ERROR << "Trying to start an unintialized application."; + return; + } + } + + const size_t io_thread_count = configuration_->get_io_thread_count(name_); + const int io_thread_nice_level = configuration_->get_io_thread_nice_level(name_); + { + std::lock_guard<std::mutex> its_lock(start_stop_mutex_); + if (io_.stopped()) { + io_.reset(); + } else if(stop_thread_.joinable()) { + VSOMEIP_ERROR << "Trying to start an already started application."; + return; + } + if (stopped_) { + { + std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_); + block_stopping_ = true; + block_stop_cv_.notify_all(); + } + + stopped_ = false; + return; + } + stopped_ = false; + stopped_called_ = false; + VSOMEIP_INFO << "Starting vsomeip application \"" << name_ << "\" (" + << std::hex << std::setw(4) << std::setfill('0') << client_ + << ") using " << std::dec << io_thread_count << " threads" +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + << " I/O nice " << io_thread_nice_level +#endif + ; + + start_caller_id_ = std::this_thread::get_id(); + { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + is_dispatching_ = true; + std::packaged_task<void()> dispatcher_task_( + std::bind(&application_impl::main_dispatch, shared_from_this())); + std::future<void> dispatcher_future_ = dispatcher_task_.get_future(); + auto its_main_dispatcher = std::make_shared<std::thread>(std::move(dispatcher_task_)); +#ifdef _WIN32 + dispatchers_control_[its_main_dispatcher->get_id()] = { + OpenThread(THREAD_ALL_ACCESS, false, + GetThreadId(its_main_dispatcher->native_handle())), + std::move(dispatcher_future_)}; +#else + dispatchers_control_[its_main_dispatcher->get_id()] = { + its_main_dispatcher->native_handle(), std::move(dispatcher_future_)}; +#endif + dispatchers_[its_main_dispatcher->get_id()] = its_main_dispatcher; + increment_active_threads(); + } + + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + stop_thread_= std::thread(&application_impl::shutdown, shared_from_this()); + + if (routing_) + routing_->start(); + + for (size_t i = 0; i < io_thread_count - 1; i++) { + auto its_thread = std::make_shared<std::thread>([this, i, io_thread_nice_level] { + VSOMEIP_INFO << "io thread id from application: " + << std::hex << std::setw(4) << std::setfill('0') + << client_ << " (" << name_ << ") is: " << std::hex + << std::this_thread::get_id() +#if defined(__linux__) || defined(ANDROID) + << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) +#endif + ; +#if defined(__linux__) || defined(ANDROID) + { + std::stringstream s; + s << std::hex << std::setw(4) << std::setfill('0') + << client_ << "_io" << std::setw(2) << i+1; + pthread_setname_np(pthread_self(),s.str().c_str()); + } + utility::set_thread_niceness(io_thread_nice_level); +#endif + while(true) { + try { + io_.run(); + break; + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::start() " + "caught exception: " << e.what(); + } + } + }); + io_threads_.insert(its_thread); + } + } + + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + for (const auto& its_library : its_app_plugin_info->second) { + auto its_application_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::APPLICATION_PLUGIN, its_library); + if (its_application_plugin) { + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_STARTED); + } + } + } + { + std::lock_guard<std::mutex> its_app_lock(app_counter_mutex__); + app_counter__++; + } + VSOMEIP_INFO << "io thread id from application: " + << std::hex << std::setw(4) << std::setfill('0') << client_ << " (" + << name_ << ") is: " << std::this_thread::get_id() +#if defined(__linux__) || defined(ANDROID) + << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) +#endif + ; + utility::set_thread_niceness(io_thread_nice_level); + while(true) { + try { + io_.run(); + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + break; + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::start() caught exception: " << e.what(); + } + } + { + std::lock_guard<std::mutex> its_lock_start_stop(block_stop_mutex_); + block_stopping_ = true; + block_stop_cv_.notify_all(); + } + + { + std::lock_guard<std::mutex> its_lock(start_stop_mutex_); + stopped_ = false; + } + { + std::lock_guard<std::mutex> its_app_lock(app_counter_mutex__); + app_counter__--; + } +} + +void application_impl::stop() { + + VSOMEIP_INFO << "Stopping vsomeip application \"" << name_ << "\" (" + << std::hex << std::setw(4) << std::setfill('0') << client_ << ")."; + + bool block = true; + { + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); + if (stopped_ || stopped_called_) { + return; + } + stop_caller_id_ = std::this_thread::get_id(); + stopped_ = true; + stopped_called_ = true; + for (const auto& thread : io_threads_) { + if (thread->get_id() == std::this_thread::get_id()) { + block = false; + } + } + if (start_caller_id_ == stop_caller_id_) { + block = false; + } + } + + if (configuration_) { + auto its_plugins = configuration_->get_plugins(name_); + auto its_app_plugin_info = its_plugins.find(plugin_type_e::APPLICATION_PLUGIN); + if (its_app_plugin_info != its_plugins.end()) { + for (const auto& its_library : its_app_plugin_info->second) { + auto its_application_plugin = plugin_manager::get()->get_plugin( + plugin_type_e::APPLICATION_PLUGIN, its_library); + if (its_application_plugin) { + std::dynamic_pointer_cast<application_plugin>(its_application_plugin)-> + on_application_state_change(name_, application_plugin_state_e::STATE_STOPPED); + } + } + + } + } + + { + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); + stop_cv_.notify_one(); + } + + if (block) { + std::unique_lock<std::mutex> block_stop_lock(block_stop_mutex_); + block_stop_cv_.wait_for(block_stop_lock, std::chrono::milliseconds(1000), + [this] { return block_stopping_.load(); }); + block_stopping_ = false; + } +} + +void application_impl::process(int _number) { + (void)_number; + VSOMEIP_ERROR << "application::process is not (yet) implemented."; +} + +security_mode_e application_impl::get_security_mode() const { + return security_mode_; +} + +void application_impl::offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + if (routing_) + routing_->offer_service(client_, _service, _instance, _major, _minor); +} + +void application_impl::stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + if (routing_) + routing_->stop_offer_service(client_, _service, _instance, _major, _minor); +} + +void application_impl::request_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + invoke_availability_handler(_service, _instance, _major, _minor); + if (routing_) + routing_->request_service(client_, _service, _instance, _major, _minor); +} + +void application_impl::release_service(service_t _service, + instance_t _instance) { + { + std::lock_guard<std::mutex> its_subscriptions_state_guard(subscriptions_state_mutex_); + auto found_service = subscriptions_state_.find(_service); + if (found_service != subscriptions_state_.end()) { + found_service->second.erase(_instance); + if (found_service->second.empty()) { + subscriptions_state_.erase(_service); + } + } + } + if (routing_) + routing_->release_service(client_, _service, _instance); +} + +void application_impl::subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + major_version_t _major, + event_t _event) { + if (routing_) { + bool send_back_cached(false); + bool send_back_cached_group(false); + check_send_back_cached_event(_service, _instance, _event, _eventgroup, + &send_back_cached, &send_back_cached_group); + + if (send_back_cached) { + send_back_cached_event(_service, _instance, _event); + } else if(send_back_cached_group) { + send_back_cached_eventgroup(_service, _instance, _eventgroup); + } + + if (check_subscription_state(_service, _instance, _eventgroup, _event)) { + routing_->subscribe(client_, &sec_client_, + _service, _instance, _eventgroup, _major, + _event, nullptr); + } + } +} + +void application_impl::unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) { + remove_subscription(_service, _instance, _eventgroup, ANY_EVENT); + if (routing_) + routing_->unsubscribe(client_, &sec_client_, _service, _instance, _eventgroup, ANY_EVENT); +} + +void application_impl::unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + remove_subscription(_service, _instance, _eventgroup, _event); + if (routing_) + routing_->unsubscribe(client_, &sec_client_, _service, _instance, _eventgroup, _event); +} + +bool application_impl::is_available( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + return (is_available_unlocked(_service, _instance, _major, _minor) + == availability_state_e::AS_AVAILABLE); +} + +availability_state_e +application_impl::is_available_unlocked( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + + availability_state_e its_state(availability_state_e::AS_UNKNOWN); + + auto check_major_minor = [&](const available_instance_t::const_iterator &_found_instance) { + auto found_major = _found_instance->second.find(_major); + if (found_major != _found_instance->second.end()) { + if (_minor <= found_major->second.first || _minor == ANY_MINOR + || _minor == DEFAULT_MINOR) { + its_state = found_major->second.second; + } + } else if (_major == DEFAULT_MAJOR || _major == ANY_MAJOR) { + for (const auto &found_major : _found_instance->second) { + if (_minor == DEFAULT_MINOR || _minor == ANY_MINOR) { + its_state = found_major.second.second; + break; + } else if (_minor <= found_major.second.first) { + its_state = found_major.second.second; + break; + } + } + } + }; + auto found_service = available_.find(_service); + if (found_service != available_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + check_major_minor(found_instance); + } else if (_instance == ANY_INSTANCE) { + for (auto it = found_service->second.cbegin(); + it != found_service->second.cend(); it++) { + check_major_minor(it); + if (its_state != availability_state_e::AS_UNKNOWN) { + break; + } + } + } + } else if (_service == ANY_SERVICE) { + for (const auto &found_service : available_) { + auto found_instance = found_service.second.find(_instance); + if (found_instance != found_service.second.end()) { + check_major_minor(found_instance); + if (its_state != availability_state_e::AS_UNKNOWN) { + break; + } + } else if (_instance == ANY_INSTANCE) { + for (auto it = found_service.second.cbegin(); + it != found_service.second.cend(); it++) { + check_major_minor(it); + if (its_state != availability_state_e::AS_UNKNOWN) { + break; + } + } + } + if (its_state != availability_state_e::AS_UNKNOWN) { + break; + } + } + } + return its_state; +} + +bool application_impl::are_available( + available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + return (are_available_unlocked(_available, _service, _instance, _major, _minor) + == availability_state_e::AS_AVAILABLE); +} + +availability_state_e +application_impl::are_available_unlocked(available_t &_available, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + + //find available services + if(_service == ANY_SERVICE) { + //add all available services + for(auto its_available_services_it = available_.begin(); + its_available_services_it != available_.end(); + ++its_available_services_it) { + _available[its_available_services_it->first]; + } + } else { + // check if specific service is available + if(available_.find(_service) != available_.end()) { + _available[_service]; + } + } + + //find available instances + //iterate through found available services + for(auto its_available_services_it = _available.begin(); + its_available_services_it != _available.end(); + ++its_available_services_it) { + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + if(_instance == ANY_INSTANCE) { + //add all available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) { + _available[its_available_services_it->first][its_available_instances_it->first]; + } + } else { + if(found_available_service->second.find(_instance) != found_available_service->second.end()) { + _available[its_available_services_it->first][_instance]; + } + } + } + } + + //find major versions + //iterate through found available services + for(auto its_available_services_it = _available.begin(); + its_available_services_it != _available.end(); + ++its_available_services_it) { + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + //iterate through found available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) { + //get available instance + auto found_available_instance = found_available_service->second.find(its_available_instances_it->first); + if(found_available_instance != found_available_service->second.end()) { + if(_major == ANY_MAJOR || _major == DEFAULT_MAJOR) { + //add all major versions + for(auto its_available_major_it = found_available_instance->second.begin(); + its_available_major_it != found_available_instance->second.end(); + ++its_available_major_it) { + _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first]; + } + } else { + if(found_available_instance->second.find(_major) != found_available_instance->second.end()) { + _available[its_available_services_it->first][its_available_instances_it->first][_major]; + } + } + } + } + } + } + + //find minor + //iterate through found available services + auto its_available_services_it = _available.begin(); + while(its_available_services_it != _available.end()) { + bool found_minor(false); + //get available service + auto found_available_service = available_.find(its_available_services_it->first); + if (found_available_service != available_.end()) { + //iterate through found available instances + for(auto its_available_instances_it = found_available_service->second.begin(); + its_available_instances_it != found_available_service->second.end(); + ++its_available_instances_it) { + //get available instance + auto found_available_instance = found_available_service->second.find(its_available_instances_it->first); + if(found_available_instance != found_available_service->second.end()) { + //iterate through found available major version + for(auto its_available_major_it = found_available_instance->second.begin(); + its_available_major_it != found_available_instance->second.end(); + ++its_available_major_it) { + //get available major version + auto found_available_major = found_available_instance->second.find(its_available_major_it->first); + if (found_available_major != found_available_instance->second.end()) { + if ((_minor == ANY_MINOR || _minor == DEFAULT_MINOR + || _minor <= found_available_major->second.first) + && availability_state_e::AS_AVAILABLE == found_available_major->second.second) { + //add minor version + _available[its_available_services_it->first][its_available_instances_it->first][its_available_major_it->first] + = found_available_major->second.first; + found_minor = true; + } + } + } + } + } + } + if(found_minor) + ++its_available_services_it; + else + its_available_services_it = _available.erase(its_available_services_it); + } + + if (_available.empty()) { + _available[_service][_instance][_major] = _minor ; + + return availability_state_e::AS_UNAVAILABLE; + } + return availability_state_e::AS_AVAILABLE; +} + +void application_impl::send(std::shared_ptr<message> _message) { + bool is_request = utility::is_request(_message); + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(_message->get_service(), ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(_message->get_service(), _message->get_instance()))))) { + VSOMEIP_INFO << "application_impl::send: (" + << std::hex << std::setfill('0') + << std::setw(4) << client_ << "): [" + << std::setw(4) << _message->get_service() << "." + << std::setw(4) << _message->get_instance() << "." + << std::setw(4) << _message->get_method() << ":" + << std::setw(4) << (is_request ? session_ : _message->get_session()) << ":" + << std::setw(4) << (is_request ? client_.load() : _message->get_client()) << "] " + << "type=" << static_cast<std::uint32_t>(_message->get_message_type()) + << " thread=" << std::this_thread::get_id(); + } + if (routing_) { + // in case of requests set the request-id (client-id|session-id) + if (is_request) { + _message->set_client(client_); + _message->set_session(get_session(true)); + } + // Always increment the session-id + (void)routing_->send(client_, _message, false); + } +} + +void application_impl::notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, bool _force) const { + + if (routing_) { + auto its_payload { + runtime::get()->create_payload(_payload->get_data(), _payload->get_length())}; + routing_->notify(_service, _instance, _event, its_payload, _force); + } +} + +void application_impl::notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force) const { + if (routing_) { + auto its_payload { + runtime::get()->create_payload(_payload->get_data(), _payload->get_length())}; + routing_->notify_one(_service, _instance, _event, its_payload, _client, _force +#ifdef VSOMEIP_ENABLE_COMPAT + , + false +#endif + ); + } +} + +void application_impl::register_state_handler(const state_handler_t &_handler) { + std::lock_guard<std::mutex> its_lock(state_handler_mutex_); + handler_ = _handler; +} + +void application_impl::unregister_state_handler() { + std::lock_guard<std::mutex> its_lock(state_handler_mutex_); + handler_ = nullptr; +} + +void application_impl::register_availability_handler(service_t _service, + instance_t _instance, const availability_handler_t &_handler, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + auto its_handler_ext = [_handler](service_t _service, instance_t _instance, + availability_state_e _state) { + _handler(_service, _instance, + (_state == availability_state_e::AS_AVAILABLE)); + }; + + register_availability_handler_unlocked(_service, _instance, + its_handler_ext, _major, _minor); +} + +void application_impl::register_availability_handler(service_t _service, + instance_t _instance, const availability_state_handler_t &_handler, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + register_availability_handler_unlocked(_service, _instance, + _handler, _major, _minor); +} + +void application_impl::invoke_availability_handler( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) { + + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + auto found_service = availability_.find(_service); + if (found_service != availability_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_major = found_instance->second.find(_major); + if (found_major == found_instance->second.end()) { + found_major = found_instance->second.find(ANY_MAJOR); + } + if (found_major != found_instance->second.end()) { + auto found_minor = found_major->second.find(_minor); + if (found_minor == found_major->second.end()) { + found_minor = found_major->second.find(ANY_MINOR); + } + if (found_minor != found_major->second.end()) { + auto its_state { is_available_unlocked(_service, _instance, _major, _minor) }; + if (availability_state_e::AS_UNKNOWN != its_state + && get_availability_state(found_minor->second.second, + _service, _instance, _major, _minor) + != its_state) { + auto its_handler {found_minor->second.first}; + set_availability_state(found_minor->second.second, _service, _instance, + _major, _minor, its_state); + + std::lock_guard<std::mutex> handlers_lock(handlers_mutex_); + auto its_sync_handler = std::make_shared<sync_handler>( + [its_handler, _service, _instance, its_state]() { + its_handler(_service, _instance, its_state); + }); + its_sync_handler->handler_type_ = handler_type_e::AVAILABILITY; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); + } + } + } + } + } +} + +void application_impl::register_availability_handler_unlocked(service_t _service, + instance_t _instance, const availability_state_handler_t &_handler, + major_version_t _major, minor_version_t _minor) { + + auto its_state {is_available_unlocked(_service, _instance, _major, _minor)}; + + availability_state_t its_availability_state; + set_availability_state(its_availability_state, _service, _instance, _major, _minor, its_state); + + availability_[_service][_instance][_major][_minor] = + std::make_pair(_handler, its_availability_state); + + std::scoped_lock handlers_lock(handlers_mutex_); + auto its_sync_handler = + std::make_shared<sync_handler>([_handler, _service, _instance, its_state]() { + _handler(_service, _instance, its_state); + }); + its_sync_handler->handler_type_ = handler_type_e::AVAILABILITY; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); +} + +void application_impl::unregister_availability_handler(service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor) { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + auto found_service = availability_.find(_service); + if (found_service != availability_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_major = found_instance->second.find(_major); + if (found_major != found_instance->second.end()) { + auto found_minor = found_major->second.find(_minor); + if (found_minor != found_major->second.end()) { + found_major->second.erase(_minor); + + if (!found_major->second.size()) { + found_instance->second.erase(_major); + if (!found_instance->second.size()) { + found_service->second.erase(_instance); + if (!found_service->second.size()) { + availability_.erase(_service); + } + } + } + } + } + } + } +} + +void application_impl::on_subscription( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + client_t _client, const vsomeip_sec_client_t *_sec_client, + const std::string &_env, bool _subscribed, + const std::function<void(bool)> &_accepted_cb) { + + bool handler_found = false; + std::pair<subscription_handler_sec_t, async_subscription_handler_sec_t> its_handlers; + { + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + auto found_service = subscription_.find(_service); + if (found_service != subscription_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + its_handlers = found_eventgroup->second; + handler_found = true; + } + } + } + } + + if (handler_found) { + if(auto its_handler = its_handlers.first) { + // "normal" subscription handler exists + _accepted_cb(its_handler(_client, _sec_client, _env, _subscribed)); + } else if(auto its_handler = its_handlers.second) { + // async subscription handler exists + its_handler(_client, _sec_client, _env, _subscribed, _accepted_cb); + } + } else { + _accepted_cb(true); + } +} + +void application_impl::register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_t &_handler) { + + subscription_handler_ext_t its_handler_ext + = [_handler](client_t _client, uid_t _uid, gid_t _gid, + const std::string &_env, bool _is_subscribed) { + + (void)_env; // compatibility + return _handler(_client, _uid, _gid, _is_subscribed); + }; + + register_subscription_handler(_service, _instance, _eventgroup, + its_handler_ext); +} + +void application_impl::register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_ext_t &_handler) { + + subscription_handler_sec_t its_handler_sec = [_handler]( + client_t _client, + const vsomeip_sec_client_t* _sec_client, + const std::string& _env, + bool _is_subscribed + ){ + uid_t its_uid {_sec_client->user}; + gid_t its_gid {_sec_client->group}; + + return _handler( + _client, + its_uid, + its_gid, + _env, + _is_subscribed + ); + }; + + register_subscription_handler(_service, _instance, _eventgroup, its_handler_sec); +} + +void application_impl::register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_sec_t &_handler) { + + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + subscription_[_service][_instance][_eventgroup] = std::make_pair(_handler, nullptr); +} + + +void application_impl::unregister_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) { + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + auto found_service = subscription_.find(_service); + if (found_service != subscription_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + found_instance->second.erase(_eventgroup); + } + } + } +} + +void application_impl::on_subscription_status( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error) { + + bool entry_found(false); + { + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_service = subscriptions_state_.find(_service); + if (its_service == subscriptions_state_.end()) { + its_service = subscriptions_state_.find(ANY_SERVICE); + } + if (its_service != subscriptions_state_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance == its_service->second.end()) { + its_instance = its_service->second.find(ANY_INSTANCE); + } + if (its_instance != its_service->second.end()) { + auto its_eventgroup = its_instance->second.find(_eventgroup); + if (its_eventgroup == its_instance->second.end()) { + its_eventgroup = its_instance->second.find(ANY_EVENTGROUP); + } + if (its_eventgroup != its_instance->second.end()) { + auto its_event = its_eventgroup->second.find(_event); + if (its_event == its_eventgroup->second.end()) { + its_event = its_eventgroup->second.find(ANY_EVENT); + } + if (its_event != its_eventgroup->second.end()) { + entry_found = true; + its_event->second = (_error ? + subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED : + subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED); + } + auto its_any_event = its_eventgroup->second.find(ANY_EVENT); + if (its_any_event != its_eventgroup->second.end()) { + entry_found = true; + its_any_event->second = (_error ? + subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED : + subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED); + } + } + } + } + } + if (entry_found) { + deliver_subscription_state(_service, _instance, _eventgroup, _event, _error); + } +} + +void application_impl::deliver_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error) { + + std::vector<subscription_status_handler_t> handlers; + { + std::lock_guard<std::mutex> its_lock(subscription_status_handlers_mutex_); + auto found_service = subscription_status_handlers_.find(_service); + if (found_service != subscription_status_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + auto found_any_eventgroup = found_instance->second.find(ANY_EVENTGROUP); + if (found_any_eventgroup != found_instance->second.end()) { + auto found_event = found_any_eventgroup->second.find(_event); + if (found_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_any_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + } + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + auto found_any_eventgroup = found_instance->second.find(ANY_EVENTGROUP); + if (found_any_eventgroup != found_instance->second.end()) { + auto found_event = found_any_eventgroup->second.find(_event); + if (found_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_any_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + } + } + found_service = subscription_status_handlers_.find(ANY_SERVICE); + if (found_service != subscription_status_handlers_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + auto found_any_eventgroup = found_instance->second.find(ANY_EVENTGROUP); + if (found_any_eventgroup != found_instance->second.end()) { + auto found_event = found_any_eventgroup->second.find(_event); + if (found_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_any_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + } + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto found_event = found_eventgroup->second.find(_event); + if (found_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + auto found_any_eventgroup = found_instance->second.find(ANY_EVENTGROUP); + if (found_any_eventgroup != found_instance->second.end()) { + auto found_event = found_any_eventgroup->second.find(_event); + if (found_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_event->second.second)) { + handlers.push_back(found_event->second.first); + } + } + auto found_any_event = found_any_eventgroup->second.find(ANY_EVENT); + if (found_any_event != found_any_eventgroup->second.end()) { + if (!_error || (_error && found_any_event->second.second)) { + handlers.push_back(found_any_event->second.first); + } + } + } + } + } + } + { + std::unique_lock<std::mutex> handlers_lock(handlers_mutex_); + for (auto &handler : handlers) { + auto its_sync_handler = std::make_shared<sync_handler>([handler, _service, + _instance, _eventgroup, + _event, _error]() { + handler(_service, _instance, + _eventgroup, _event, _error); + }); + its_sync_handler->handler_type_ = handler_type_e::SUBSCRIPTION; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + its_sync_handler->method_id_ = _event; + its_sync_handler->eventgroup_id_ = _eventgroup; + handlers_.push_back(its_sync_handler); + } + if (handlers.size()) { + dispatcher_condition_.notify_one(); + } + } +} + +void application_impl::register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective) { + std::lock_guard<std::mutex> its_lock(subscription_status_handlers_mutex_); + if (_handler) { + subscription_status_handlers_[_service][_instance][_eventgroup][_event] = + std::make_pair(_handler, _is_selective); + } else { + VSOMEIP_WARNING << + "application_impl::register_subscription_status_handler: " + "_handler is null, for unregistration please use " + "application_impl::unregister_subscription_status_handler [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "." + << std::setw(4) << _event << "]"; + } +} + +void application_impl::unregister_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event) { + std::lock_guard<std::mutex> its_lock(subscription_status_handlers_mutex_); + auto its_service = subscription_status_handlers_.find(_service); + if (its_service != subscription_status_handlers_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_eventgroup = its_instance->second.find(_eventgroup); + if (its_eventgroup != its_instance->second.end()) { + its_eventgroup->second.erase(_event); + if (its_eventgroup->second.empty()) { + its_instance->second.erase(_eventgroup); + if (its_instance->second.empty()) { + its_service->second.erase(_instance); + if (its_service->second.empty()) { + subscription_status_handlers_.erase(_service); + } + } + } + } + } + } +} + +void application_impl::register_message_handler(service_t _service, + instance_t _instance, method_t _method, const message_handler_t &_handler) { + + register_message_handler_ext(_service, _instance, _method, _handler, + handler_registration_type_e::HRT_REPLACE); +} + +void application_impl::unregister_message_handler(service_t _service, + instance_t _instance, method_t _method) { + std::lock_guard<std::mutex> its_lock(members_mutex_); + members_.erase(to_members_key(_service, _instance, _method)); +} + +void application_impl::offer_event(service_t _service, instance_t _instance, + event_t _notifier, const std::set<eventgroup_t> &_eventgroups, + event_type_e _type, + std::chrono::milliseconds _cycle, bool _change_resets_cycle, + bool _update_on_change, + const epsilon_change_func_t &_epsilon_change_func, + reliability_type_e _reliability) { + if (routing_) { + + if (_cycle == std::chrono::milliseconds::zero() + && _change_resets_cycle == false + && _update_on_change == true) { + + configuration_->get_event_update_properties( + _service, _instance, _notifier, + _cycle, _change_resets_cycle, _update_on_change); + + VSOMEIP_INFO << __func__ + << std::hex << std::setfill('0') + << ": Event [" << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _notifier + << "] uses configured cycle time " + << std::dec << _cycle.count() << "ms"; + } + + routing_->register_event(client_, + _service, _instance, + _notifier, _eventgroups, _type, _reliability, + _cycle, _change_resets_cycle, _update_on_change, + _epsilon_change_func, true); + } +} + +void application_impl::stop_offer_event(service_t _service, instance_t _instance, + event_t _event) { + if (routing_) + routing_->unregister_event(client_, _service, _instance, _event, true); +} + +void application_impl::request_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + event_type_e _type, reliability_type_e _reliability) { + if (routing_) + routing_->register_event(client_, + _service, _instance, + _event, _eventgroups, _type, _reliability, + std::chrono::milliseconds::zero(), false, true, + nullptr, + false); +} + +void application_impl::release_event(service_t _service, instance_t _instance, + event_t _event) { + if (routing_) + routing_->unregister_event(client_, _service, _instance, _event, false); +} + +// Interface "routing_manager_host" +const std::string & application_impl::get_name() const { + return name_; +} + +client_t application_impl::get_client() const { + return client_; +} + +void application_impl::set_client(const client_t &_client) { + client_ = _client; +} + +session_t application_impl::get_session(bool _is_request) { + + if (!has_session_handling_ && !_is_request) + return 0; + + std::lock_guard<std::mutex> its_lock(session_mutex_); + if (0 == ++session_) { + // Smallest allowed session identifier + session_ = 1; + } + + return session_; +} + +const vsomeip_sec_client_t *application_impl::get_sec_client() const { + return &sec_client_; +} + +void application_impl::set_sec_client_port(port_t _port) { + + sec_client_.port = htons(_port); +} + +std::shared_ptr<configuration> application_impl::get_configuration() const { + return configuration_; +} + +std::shared_ptr<policy_manager> application_impl::get_policy_manager() const { +#ifndef VSOMEIP_DISABLE_SECURITY + return configuration_->get_policy_manager(); +#endif + VSOMEIP_WARNING << __func__ << ": manager is not available when security is disabled."; + return {}; +} + +diagnosis_t application_impl::get_diagnosis() const { + return configuration_->get_diagnosis_address(); +} + +boost::asio::io_context &application_impl::get_io() { + return io_; +} + +void application_impl::on_state(state_type_e _state) { + + bool has_state_handler(false); + state_handler_t handler = nullptr; + { + std::lock_guard<std::mutex> its_lock(state_handler_mutex_); + if (handler_) { + has_state_handler = true; + handler = handler_; + } + } + if (has_state_handler) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + auto its_sync_handler = std::make_shared<sync_handler>([handler, _state]() { + handler(_state); + }); + its_sync_handler->handler_type_ = handler_type_e::STATE; + handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); + } +} + +availability_state_e +application_impl::get_availability_state(const availability_state_t& _availability_state, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor) const { + availability_state_e its_state {availability_state_e::AS_UNKNOWN}; + + if (auto found_service = _availability_state.find(_service); + found_service != _availability_state.end()) { + if (auto found_instance = found_service->second.find(_instance); + found_instance != found_service->second.end()) { + if (auto found_major = found_instance->second.find(_major); + found_major != found_instance->second.end()) { + if (auto found_minor = found_major->second.find(_minor); + found_minor != found_major->second.end()) { + its_state = found_minor->second; + } + } + } + } + + return its_state; +} + +void application_impl::set_availability_state(availability_state_t& _availability_state, + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + availability_state_e _state) const { + _availability_state[_service][_instance][_major][_minor] = _state; +} + +void application_impl::on_availability(service_t _service, instance_t _instance, + availability_state_e _state, major_version_t _major, minor_version_t _minor) { + + std::vector<availability_state_handler_t> its_handlers; + { + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + if (_state == is_available_unlocked(_service, _instance, _major, _minor)) { + return; + } + + if (_state != availability_state_e::AS_UNAVAILABLE) { + available_[_service][_instance][_major] = std::make_pair(_minor, _state); + } else { + auto found_available_service = available_.find(_service); + if (found_available_service != available_.end()) { + auto found_instance = found_available_service->second.find(_instance); + if( found_instance != found_available_service->second.end()) { + auto found_major = found_instance->second.find(_major); + if( found_major != found_instance->second.end() ){ + if(_minor == found_major->second.first) + found_available_service->second.erase(_instance); + } + } + } + } + + auto find_matching_handler = + [&](availability_major_minor_t& _av_ma_mi_it) { + auto found_major = _av_ma_mi_it.find(_major); + if (found_major != _av_ma_mi_it.end()) { + for (std::int32_t mi = static_cast<std::int32_t>(_minor); mi >= 0; mi--) { + auto found_minor = found_major->second.find(static_cast<minor_version_t>(mi)); + if (found_minor != found_major->second.end()) { + if (get_availability_state(found_minor->second.second, _service, _instance, + _major, _minor) != _state) { + its_handlers.push_back(found_minor->second.first); + set_availability_state(found_minor->second.second, _service, _instance, + _major, _minor, _state); + } + } + } + auto found_any_minor = found_major->second.find(ANY_MINOR); + if (found_any_minor != found_major->second.end()) { + if (get_availability_state(found_any_minor->second.second, _service, _instance, + _major, _minor) != _state) { + its_handlers.push_back(found_any_minor->second.first); + set_availability_state(found_any_minor->second.second, _service, _instance, + _major, _minor, _state); + } + } + } + found_major = _av_ma_mi_it.find(ANY_MAJOR); + if (found_major != _av_ma_mi_it.end()) { + for (std::int32_t mi = static_cast<std::int32_t>(_minor); mi >= 0; mi--) { + auto found_minor = found_major->second.find(static_cast<minor_version_t>(mi)); + if (found_minor != found_major->second.end()) { + if (get_availability_state(found_minor->second.second, _service, _instance, + _major, _minor) != _state) { + its_handlers.push_back(found_minor->second.first); + set_availability_state(found_minor->second.second, _service, _instance, + _major, _minor, _state); + } + } + } + auto found_any_minor = found_major->second.find(ANY_MINOR); + if (found_any_minor != found_major->second.end()) { + if (get_availability_state(found_any_minor->second.second, _service, _instance, + _major, _minor) != _state) { + its_handlers.push_back(found_any_minor->second.first); + set_availability_state(found_any_minor->second.second, _service, _instance, + _major, _minor, _state); + } + } + } + }; + + auto found_service = availability_.find(_service); + if (found_service != availability_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + find_matching_handler(found_instance->second); + } + found_instance = found_service->second.find(ANY_INSTANCE); + if (found_instance != found_service->second.end()) { + find_matching_handler(found_instance->second); + } + } + found_service = availability_.find(ANY_SERVICE); + if (found_service != availability_.end()) { + auto found_instance = found_service->second.find(_instance); + if( found_instance != found_service->second.end()) { + find_matching_handler(found_instance->second); + } + found_instance = found_service->second.find(ANY_INSTANCE); + if( found_instance != found_service->second.end()) { + find_matching_handler(found_instance->second); + } + } + { + std::lock_guard<std::mutex> handlers_lock(handlers_mutex_); + for (const auto &handler : its_handlers) { + auto its_sync_handler = std::make_shared<sync_handler>( + [handler, _service, _instance, _state]() + { + handler(_service, _instance, _state); + }); + its_sync_handler->handler_type_ = handler_type_e::AVAILABILITY; + its_sync_handler->service_id_ = _service; + its_sync_handler->instance_id_ = _instance; + handlers_.push_back(its_sync_handler); + } + } + } + if (_state == availability_state_e::AS_UNAVAILABLE) { + { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + auto found_service = subscriptions_.find(_service); + if (found_service != subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto &event : found_instance->second) { + for (auto &eventgroup : event.second) { + eventgroup.second = false; + } + } + } + } + } + { + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_service = subscriptions_state_.find(_service); + if (its_service != subscriptions_state_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + for (auto &its_eventgroup : its_instance->second) { + for (auto &its_event : its_eventgroup.second) { + its_event.second + = subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED; + } + } + } + } + } + } + + if (its_handlers.size()) { + std::lock_guard<std::mutex> handlers_lock(handlers_mutex_); + dispatcher_condition_.notify_one(); + } +} + +const std::deque<message_handler_t>& application_impl::find_handlers(service_t _service, instance_t _instance, method_t _method) const { + + // The (ordered!) sequence of queries to attempt + const std::array<members_key_t, 8> queries { + to_members_key(_service, _instance, _method), + to_members_key(_service, _instance, ANY_METHOD), + to_members_key(_service, ANY_INSTANCE, _method), + to_members_key(_service, ANY_INSTANCE, ANY_METHOD), + to_members_key(ANY_SERVICE, _instance, _method), + to_members_key(ANY_SERVICE, _instance, ANY_METHOD), + to_members_key(ANY_SERVICE, ANY_INSTANCE, _method), + to_members_key(ANY_SERVICE, ANY_INSTANCE, ANY_METHOD) + }; + + for (const auto query : queries) { + const auto& search = members_.find(query); + if (search != members_.end()) { + return search->second; + } + } + + static const std::deque<message_handler_t> empty; + return empty; +} + +void application_impl::on_message(std::shared_ptr<message> &&_message) { + const service_t its_service = _message->get_service(); + const instance_t its_instance = _message->get_instance(); + const method_t its_method = _message->get_method(); + + if (_message->get_message_type() == message_type_e::MT_NOTIFICATION) { + if (!check_for_active_subscription(its_service, its_instance, + static_cast<event_t>(its_method))) { + VSOMEIP_INFO << "application_impl::on_message [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_method << "]" + << ": blocked as the subscription is already inactive."; + return; + } + } + + { + std::lock_guard<std::mutex> its_lock(members_mutex_); + + const auto its_handlers = find_handlers(its_service, its_instance, its_method); + + if (!its_handlers.empty()) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + for (const auto &handler : its_handlers) { + auto its_sync_handler = + std::make_shared<sync_handler>([handler, _message]() { + handler(_message); + }); + its_sync_handler->handler_type_ = handler_type_e::MESSAGE; + its_sync_handler->service_id_ = _message->get_service(); + its_sync_handler->instance_id_ = _message->get_instance(); + its_sync_handler->method_id_ = _message->get_method(); + its_sync_handler->session_id_ = _message->get_session(); + handlers_.push_back(its_sync_handler); + } + dispatcher_condition_.notify_one(); + } + } +} + +// Interface "service_discovery_host" +routing_manager * application_impl::get_routing_manager() const { + return routing_.get(); +} + +void application_impl::main_dispatch() { + utility::set_thread_niceness(configuration_->get_io_thread_nice_level(name_)); +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + { + std::stringstream s; + s << std::hex << std::setw(4) << std::setfill('0') + << client_ << "_m_dispatch"; + pthread_setname_np(pthread_self(),s.str().c_str()); + } +#endif + const std::thread::id its_id = std::this_thread::get_id(); + VSOMEIP_INFO << "main dispatch thread id from application: " + << std::hex << std::setw(4) << std::setfill('0') << client_ << " (" + << name_ << ") is: " << std::hex << its_id +#if defined(__linux__) || defined(ANDROID) + << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) +#endif + ; + std::unique_lock<std::mutex> its_lock(handlers_mutex_); + while (is_dispatching_) { + if (handlers_.empty() || !is_active_dispatcher(its_id)) { + // Cancel other waiting dispatcher + dispatcher_condition_.notify_all(); + // Wait for new handlers to execute + while (is_dispatching_ && (handlers_.empty() || !is_active_dispatcher(its_id))) { + dispatcher_condition_.wait(its_lock); + } + } else { + std::shared_ptr<sync_handler> its_handler; + while (is_dispatching_ && is_active_dispatcher(its_id) + && (its_handler = get_next_handler())) { + its_lock.unlock(); + invoke_handler(its_handler); + + if (!is_dispatching_) + return; + + its_lock.lock(); + + reschedule_availability_handler(its_handler); + remove_elapsed_dispatchers(); + +#ifdef _WIN32 + if(!is_dispatching_) { + its_lock.unlock(); + return; + } +#endif + } + } + } + its_lock.unlock(); +} + +void application_impl::dispatch() { +#if defined(__linux__) || defined(ANDROID) + { + std::stringstream s; + s << std::hex << std::setw(4) << std::setfill('0') + << client_ << "_dispatch"; + pthread_setname_np(pthread_self(),s.str().c_str()); + } +#endif + const std::thread::id its_id = std::this_thread::get_id(); + VSOMEIP_INFO << "dispatch thread id from application: " + << std::hex << std::setw(4) << std::setfill('0') << client_ << " (" + << name_ << ") is: " << std::hex << its_id +#if defined(__linux__) || defined(ANDROID) + << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) +#endif + ; + std::unique_lock<std::mutex> its_lock(handlers_mutex_); + while (is_active_dispatcher(its_id)) { + if (is_dispatching_ && handlers_.empty()) { + dispatcher_condition_.wait(its_lock); + // Maybe woken up from main dispatcher + if (handlers_.empty() && !is_active_dispatcher(its_id)) { + if (!is_dispatching_) { + return; + } + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(its_id); + return; + } + } else { + std::shared_ptr<sync_handler> its_handler; + while (is_dispatching_ && is_active_dispatcher(its_id) + && (its_handler = get_next_handler())) { + its_lock.unlock(); + invoke_handler(its_handler); + + if (!is_dispatching_) + return; + + its_lock.lock(); + + reschedule_availability_handler(its_handler); + remove_elapsed_dispatchers(); + } + } + } + if (is_dispatching_) { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + elapsed_dispatchers_.insert(its_id); + } + dispatcher_condition_.notify_all(); +} + +std::shared_ptr<application_impl::sync_handler> application_impl::get_next_handler() { + std::shared_ptr<sync_handler> its_next_handler; + while (!handlers_.empty() && !its_next_handler) { + its_next_handler = handlers_.front(); + handlers_.pop_front(); + + // Check handler + if (its_next_handler->handler_type_ == handler_type_e::AVAILABILITY) { + const std::pair<service_t, instance_t> its_si_pair = std::make_pair( + its_next_handler->service_id_, + its_next_handler->instance_id_); + auto found_si = availability_handlers_.find(its_si_pair); + if (found_si != availability_handlers_.end() + && !found_si->second.empty() + && found_si->second.front() != its_next_handler) { + found_si->second.push_back(its_next_handler); + // There is a running availability handler for this service. + // Therefore, this one must wait... + its_next_handler = nullptr; + } else { + availability_handlers_[its_si_pair].push_back(its_next_handler); + } + } else if (its_next_handler->handler_type_ == handler_type_e::MESSAGE) { + const std::pair<service_t, instance_t> its_si_pair = std::make_pair( + its_next_handler->service_id_, + its_next_handler->instance_id_); + auto found_si = availability_handlers_.find(its_si_pair); + if (found_si != availability_handlers_.end() + && found_si->second.size() > 1) { + // The message comes after the next availability handler + // Therefore, queue it to the last one + found_si->second.push_back(its_next_handler); + its_next_handler = nullptr; + } + } + } + + return its_next_handler; +} + +void application_impl::reschedule_availability_handler( + const std::shared_ptr<sync_handler> &_handler) { + if (_handler->handler_type_ == handler_type_e::AVAILABILITY) { + const std::pair<service_t, instance_t> its_si_pair = std::make_pair( + _handler->service_id_, _handler->instance_id_); + auto found_si = availability_handlers_.find(its_si_pair); + if (found_si != availability_handlers_.end()) { + if (!found_si->second.empty() + && found_si->second.front() == _handler) { + found_si->second.pop_front(); + + // If there are other availability handlers pending, schedule + // them and all handlers that were queued because of them + for (auto it = found_si->second.rbegin(); + it != found_si->second.rend(); it++) { + handlers_.push_front(*it); + } + availability_handlers_.erase(found_si); + } + return; + } + VSOMEIP_WARNING << __func__ + << ": An unknown availability handler returned!"; + } +} + +void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) { + const std::thread::id its_id = std::this_thread::get_id(); + + auto its_sync_handler = std::make_shared<sync_handler>(_handler->service_id_, + _handler->instance_id_, _handler->method_id_, + _handler->session_id_, _handler->eventgroup_id_, + _handler->handler_type_); + + boost::asio::steady_timer its_dispatcher_timer(io_); + its_dispatcher_timer.expires_from_now(std::chrono::milliseconds(max_dispatch_time_)); + its_dispatcher_timer.async_wait([this, its_sync_handler](const boost::system::error_code &_error) { + if (!_error) { + print_blocking_call(its_sync_handler); + if (has_active_dispatcher()) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + dispatcher_condition_.notify_all(); + } else { + // If possible, create a new dispatcher thread to unblock. + // If this is _not_ possible, dispatching is blocked until + // at least one of the active handler calls returns. + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + if (dispatchers_.size() < max_dispatchers_) { + if (is_dispatching_) { + std::packaged_task<void()> dispatcher_task_( + std::bind(&application_impl::dispatch, shared_from_this())); + std::future<void> dispatcher_future_ = + dispatcher_task_.get_future(); + auto its_dispatcher = + std::make_shared<std::thread>(std::move(dispatcher_task_)); +#ifdef _WIN32 + dispatchers_control_[its_dispatcher->get_id()] = { + OpenThread(THREAD_ALL_ACCESS, false, + GetThreadId(its_dispatcher->native_handle())), + std::move(dispatcher_future_)}; +#else + dispatchers_control_[its_dispatcher->get_id()] = { + its_dispatcher->native_handle(), + std::move(dispatcher_future_)}; +#endif + dispatchers_[its_dispatcher->get_id()] = its_dispatcher; + increment_active_threads(); + } else { + VSOMEIP_INFO << "Won't start new dispatcher " + "thread as Client=" << std::hex + << get_client() << " is shutting down"; + } + } else { + VSOMEIP_ERROR << "Maximum number of dispatchers exceeded. Configuration: " + << " Max dispatchers: " << std::dec << max_dispatchers_ + << " Max dispatch time: " << std::dec << max_dispatch_time_; + } + dispatcher_mutex_.unlock(); + break; + } else { + std::this_thread::yield(); + } + } + } + } + }); + if (client_side_logging_ + && (client_side_logging_filter_.empty() + || (1 == client_side_logging_filter_.count(std::make_tuple(its_sync_handler->service_id_, ANY_INSTANCE))) + || (1 == client_side_logging_filter_.count(std::make_tuple(its_sync_handler->service_id_, its_sync_handler->instance_id_))))) { + VSOMEIP_INFO << "Invoking handler: (" + << std::hex << std::setfill('0') + << std::setw(4) << client_ << "): [" + << std::setw(4) << its_sync_handler->service_id_ << "." + << std::setw(4) << its_sync_handler->instance_id_ << "." + << std::setw(4) << its_sync_handler->method_id_ << ":" + << std::setw(4) << its_sync_handler->session_id_ << "] " + << "type=" << static_cast<std::uint32_t>(its_sync_handler->handler_type_) + << " thread=" << std::hex << its_id; + } + + while (is_dispatching_ ) { + if (dispatcher_mutex_.try_lock()) { + running_dispatchers_.insert(its_id); + dispatcher_mutex_.unlock(); + break; + } + std::this_thread::yield(); + } + + if (is_dispatching_) { + try { + _handler->handler_(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::invoke_handler caught exception: " + << e.what(); + print_blocking_call(its_sync_handler); + } + } + boost::system::error_code ec; + its_dispatcher_timer.cancel(ec); + + while (is_dispatching_ ) { + if (dispatcher_mutex_.try_lock()) { + running_dispatchers_.erase(its_id); + dispatcher_mutex_.unlock(); + return; + } + std::this_thread::yield(); + } +} + +bool application_impl::has_active_dispatcher() { + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + for (const auto &d : dispatchers_) { + if (running_dispatchers_.find(d.first) == running_dispatchers_.end() && + elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { + dispatcher_mutex_.unlock(); + return true; + } + } + dispatcher_mutex_.unlock(); + return false; + } + std::this_thread::yield(); + } + return false; +} + +bool application_impl::is_active_dispatcher(const std::thread::id &_id) const { + while (is_dispatching_) { + if (dispatcher_mutex_.try_lock()) { + for (const auto &d : dispatchers_) { + if (d.first != _id && + running_dispatchers_.find(d.first) == running_dispatchers_.end() && + elapsed_dispatchers_.find(d.first) == elapsed_dispatchers_.end()) { + dispatcher_mutex_.unlock(); + return false; + } + } + dispatcher_mutex_.unlock(); + return true; + } + std::this_thread::yield(); + } + return false; +} + +void application_impl::remove_elapsed_dispatchers() { + if (is_dispatching_) { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (auto id : elapsed_dispatchers_) { + if (auto its_dispatcher = dispatchers_.find(id); its_dispatcher->second->joinable()) { + dispatchers_control_.erase(id); + its_dispatcher->second->join(); + decrement_active_threads(); + } + + dispatchers_.erase(id); + } + elapsed_dispatchers_.clear(); + } +} + +void application_impl::clear_all_handler() { + unregister_state_handler(); + { + std::lock_guard<std::mutex> its_lock(offered_services_handler_mutex_); + offered_services_handler_ = nullptr; + } + + { + std::lock_guard<std::mutex> availability_lock(availability_mutex_); + availability_.clear(); + } + + { + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + subscription_.clear(); + } + + { + std::lock_guard<std::mutex> its_lock(subscription_error_mutex_); + eventgroup_error_handlers_.clear(); + } + + { + std::lock_guard<std::mutex> its_lock(members_mutex_); + members_.clear(); + } + { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + handlers_.clear(); + } +} + +void application_impl::shutdown() { + VSOMEIP_INFO << "shutdown thread id from application: " + << std::hex << std::setw(4) << std::setfill('0') << client_ << " (" + << name_ << ") is: " << std::hex << std::this_thread::get_id() +#if defined(__linux__) || defined(ANDROID) + << " TID: " << std::dec << static_cast<int>(syscall(SYS_gettid)) +#endif + ; +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + boost::asio::detail::posix_signal_blocker blocker; + { + std::stringstream s; + s << std::hex << std::setw(4) << std::setfill('0') + << client_ << "_shutdown"; + pthread_setname_np(pthread_self(),s.str().c_str()); + } +#endif + + { + std::unique_lock<std::mutex> its_lock(start_stop_mutex_); + while(!stopped_) { + stop_cv_.wait(its_lock); + } + } + { + std::lock_guard<std::mutex> its_handler_lock(handlers_mutex_); + is_dispatching_ = false; + dispatcher_condition_.notify_all(); + } + + try { + std::lock_guard<std::mutex> its_lock(dispatcher_mutex_); + for (const auto& its_dispatcher : dispatchers_) { + if (its_dispatcher.second->get_id() != stop_caller_id_) { + if (its_dispatcher.second->joinable()) { + dispatchers_control_.erase(its_dispatcher.second->get_id()); + its_dispatcher.second->join(); + decrement_active_threads(); + } + } else { + // If the caller of stop() is one of our dispatchers + // it can happen the shutdown mechanism will block + // as that thread probably can't be joined. The reason + // is the caller of stop() probably wants to join the + // thread once call start (which got to the IO-Thread) + // and which is expected to return after stop() has been + // called. + // Therefore detach this thread instead of joining because + // after it will return to "main_dispatch" it will be + // properly shutdown anyways because "is_dispatching_" + // was set to "false" here. + + its_dispatcher.second->detach(); + } + } + availability_handlers_.clear(); + running_dispatchers_.clear(); + elapsed_dispatchers_.clear(); + dispatchers_.clear(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::" << __func__ << ": stopping dispatchers, " + << " catched exception: " << e.what(); + } + + try { + if (routing_) + routing_->stop(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::" << __func__ << ": stopping routing, " + << " catched exception: " << e.what(); + } + + try { + while (get_active_threads() > 0) { + auto its_dispatcher_control_ = dispatchers_control_.begin(); + bool os_flag_ = false; + + if (its_dispatcher_control_ != dispatchers_control_.end()) { + if (std::get<1>(its_dispatcher_control_->second) + .wait_for(std::chrono::seconds(max_detached_thread_wait_time)) + == std::future_status::timeout) { + +#ifdef _WIN32 + TerminateThread(std::get<0>(its_dispatcher_control_->second), 0); +#else + pthread_t thread_to_kill = std::get<0>(its_dispatcher_control_->second); + + // Using pthread_cancel for UNIX based systems and pthread_kill(SIGKILL) + // for android since pthread_cancel is not implemented on android. + // The major difference is that pthread_cancel allows for signal handling + // and proper resource cleanup to be done on the application side + // while pthread_kill(SIGKILL) stops the thread immediately. + // This should not however be an issue since this will only be called + // if the thread is already stuck for some time during app->stop() +#if defined(ANDROID) + os_flag_ = true; + if (pthread_kill(thread_to_kill, SIGKILL) != 0) { +#elif defined(__linux__) || defined(__QNX__) + if (pthread_cancel(thread_to_kill) != 0) { +#endif + VSOMEIP_ERROR + << "[OS=" << (os_flag_ ? "ANDROID" : "UNIX") << "] " + << "Failed to kill detached thread with id: " << std::hex + << its_dispatcher_control_->first + << "; Number of threads still active : " << get_active_threads(); + } else { + decrement_active_threads(); + VSOMEIP_INFO + << "[OS=" << (os_flag_ ? "ANDROID" : "UNIX") << "] " + << "Force killed thread with id: " << std::hex + << its_dispatcher_control_->first + << "; Number of threads still active : " << get_active_threads(); + dispatchers_control_.erase(its_dispatcher_control_); + } +#endif + } else { + decrement_active_threads(); + VSOMEIP_INFO << "[OS=" << (os_flag_ ? "ANDROID" : "UNIX") << "] " + << "Detached thread with id: " << std::hex + << its_dispatcher_control_->first << " exited successfully" + << "; Number of threads still active : " << get_active_threads(); + dispatchers_control_.erase(its_dispatcher_control_); + } + } + } + } catch (const std::exception& e) { + VSOMEIP_ERROR << "application_impl::" << __func__ + << ": waiting for detached threads to finish execution, " + << " catched exception: " << e.what(); + } + + try { + work_.reset(); + io_.stop(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::" << __func__ << ": stopping io, " + << " catched exception: " << e.what(); + } + + try { + std::lock_guard<std::mutex> its_lock_start_stop(start_stop_mutex_); + for (const auto& t : io_threads_) { + if (t->joinable()) { + t->join(); + } + } + io_threads_.clear(); + } catch (const std::exception &e) { + VSOMEIP_ERROR << "application_impl::" << __func__ << ": joining threads, " + << " catched exception: " << e.what(); + } +} + +bool application_impl::is_routing() const { + return is_routing_manager_host_; +} + +void application_impl::send_back_cached_event(service_t _service, + instance_t _instance, + event_t _event) { + std::shared_ptr<event> its_event = routing_->find_event(_service, + _instance, _event); + if (its_event && its_event->is_field() && its_event->is_set()) { + std::shared_ptr<message> its_message = runtime_->create_notification(); + its_message->set_service(_service); + its_message->set_method(_event); + its_message->set_instance(_instance); + its_message->set_payload(its_event->get_payload()); + its_message->set_initial(true); + on_message(std::move(its_message)); + VSOMEIP_INFO << "Sending back cached event (" + << std::hex << std::setfill('0') + << std::setw(4) << client_ << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _event << "]"; + } +} + +void application_impl::send_back_cached_eventgroup(service_t _service, + instance_t _instance, + eventgroup_t _eventgroup) { + std::set<std::shared_ptr<event>> its_events = routing_->find_events(_service, _instance, + _eventgroup); + for(const auto &its_event : its_events) { + if (its_event && its_event->is_field() && its_event->is_set()) { + std::shared_ptr<message> its_message = runtime_->create_notification(); + const event_t its_event_id(its_event->get_event()); + its_message->set_service(_service); + its_message->set_method(its_event_id); + its_message->set_instance(_instance); + its_message->set_payload(its_event->get_payload()); + its_message->set_initial(true); + on_message(std::move(its_message)); + VSOMEIP_INFO << "Sending back cached event (" + << std::hex << std::setfill('0') + << std::setw(4) << client_ << "): [" + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << its_event_id + << "] from eventgroup " + << std::setw(4) << _eventgroup; + } + } +} + +void application_impl::set_routing_state(routing_state_e _routing_state) { + if (routing_) + routing_->set_routing_state(_routing_state); +} + +void application_impl::check_send_back_cached_event( + service_t _service, instance_t _instance, event_t _event, + eventgroup_t _eventgroup, bool *_send_back_cached_event, + bool *_send_back_cached_eventgroup) { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + *_send_back_cached_event = false; + *_send_back_cached_eventgroup = false; + bool already_subscribed(false); + auto found_service = subscriptions_.find(_service); + if(found_service != subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + auto found_eventgroup = found_event->second.find(_eventgroup); + if (found_eventgroup != found_event->second.end()) { + already_subscribed = true; + if (found_eventgroup->second) { + // initial values for this event have already been + // received, send back cached value + if(_event == ANY_EVENT) { + *_send_back_cached_eventgroup = true; + } else { + *_send_back_cached_event = true; + } + } + } + } + } + } + + if (!already_subscribed) { + subscriptions_[_service][_instance][_event][_eventgroup] = false; + } +} + +void application_impl::remove_subscription(service_t _service, + instance_t _instance, + eventgroup_t _eventgroup, + event_t _event) { + + { + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_service = subscriptions_state_.find(_service); + if (its_service != subscriptions_state_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + if (_event == ANY_EVENT) { + its_instance->second.erase(_eventgroup); + } else { + auto its_eventgroup = its_instance->second.find(_eventgroup); + if (its_eventgroup != its_instance->second.end()) { + its_eventgroup->second.erase(_event); + if (its_eventgroup->second.empty()) { + its_instance->second.erase(_eventgroup); + } + } + } + if (its_instance->second.empty()) + its_service->second.erase(its_instance); + } + if (its_service->second.empty()) + subscriptions_state_.erase(its_service); + } + } + + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + + auto found_service = subscriptions_.find(_service); + if(found_service != subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + if (found_event->second.erase(_eventgroup)) { + if (!found_event->second.size()) { + found_instance->second.erase(_event); + if (!found_instance->second.size()) { + found_service->second.erase(_instance); + if (!found_service->second.size()) { + subscriptions_.erase(_service); + } + } + } + } + } + } + } +} + +bool application_impl::check_for_active_subscription(service_t _service, + instance_t _instance, + event_t _event) { + std::lock_guard<std::mutex> its_lock(subscriptions_mutex_); + auto found_service = subscriptions_.find(_service); + if(found_service != subscriptions_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_event = found_instance->second.find(_event); + if (found_event != found_instance->second.end()) { + if (found_event->second.size()) { + for (auto &eventgroup : found_event->second) { + eventgroup.second = true; + } + return true; + } + } else { + // Received a event which nobody yet explicitly subscribed to. + // Check if someone subscribed to ANY_EVENT for one of + // the received event's eventgroups + auto found_any_event = found_instance->second.find(ANY_EVENT); + if (found_any_event != found_instance->second.end()) { + if (routing_) { + std::shared_ptr<event> its_event = routing_->find_event( + _service, _instance, _event); + if (its_event) { + for (const auto eg : its_event->get_eventgroups()) { + auto found_eventgroup = found_any_event->second.find(eg); + if (found_eventgroup != found_any_event->second.end()) { + // set the flag for initial event received to true + // even if we might not already received all of the + // eventgroups events. + found_eventgroup->second = true; + return true; + } + } + } + } + } + } + } + } + // Return false if an event was received from: + // - a service which nobody yet subscribed to + // - a service instance which nobody yet subscribed to + // - a service instance and nobody yet subscribed to one of the event's + // eventgroups + return false; +} + +bool application_impl::check_subscription_state(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) { + + bool is_acknowledged(false); + bool should_subscribe(true); + { + bool has_found(false); + + std::lock_guard<std::mutex> its_lock(subscriptions_state_mutex_); + auto its_service = subscriptions_state_.find(_service); + if (its_service != subscriptions_state_.end()) { + auto its_instance = its_service->second.find(_instance); + if (its_instance != its_service->second.end()) { + auto its_eventgroup = its_instance->second.find(_eventgroup); + if (its_eventgroup != its_instance->second.end()) { + auto its_event = its_eventgroup->second.find(_event); + if (its_event != its_eventgroup->second.end()) { + if (its_event->second != subscription_state_e::SUBSCRIPTION_NOT_ACKNOWLEDGED) { + has_found = true; + + // only return true if subscription is NACK + // as only then we need to subscribe! + should_subscribe = false; + if (its_event->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) { + is_acknowledged = true; + } + } + } + } + } + } + + if (!has_found) { + subscriptions_state_[_service][_instance][_eventgroup][_event] + = subscription_state_e::IS_SUBSCRIBING; + } + } + + if (!should_subscribe && is_acknowledged) { + // Deliver subscription state only if ACK has already received + deliver_subscription_state(_service, _instance, _eventgroup, _event, 0 /* OK */); + } + + return should_subscribe; +} + +void application_impl::print_blocking_call(const std::shared_ptr<sync_handler>& _handler) { + switch (_handler->handler_type_) { + case handler_type_e::AVAILABILITY: + VSOMEIP_WARNING << "BLOCKING CALL AVAILABILITY(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << _handler->service_id_ << "." + << std::setw(4) << _handler->instance_id_ << "]"; + break; + case handler_type_e::MESSAGE: + VSOMEIP_WARNING << "BLOCKING CALL MESSAGE(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << _handler->service_id_ << "." + << std::setw(4) << _handler->instance_id_ << "." + << std::setw(4) << _handler->method_id_ << ":" + << std::setw(4) << _handler->session_id_ << "]"; + break; + case handler_type_e::STATE: + VSOMEIP_WARNING << "BLOCKING CALL STATE(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + break; + case handler_type_e::SUBSCRIPTION: + VSOMEIP_WARNING << "BLOCKING CALL SUBSCRIPTION(" + << std::hex << std::setfill('0') + << std::setw(4) << get_client() << "): [" + << std::setw(4) << _handler->service_id_ << "." + << std::setw(4) << _handler->instance_id_ << "." + << std::setw(4) << _handler->eventgroup_id_ << ":" + << std::setw(4) << _handler->method_id_ << "]"; + break; + case handler_type_e::OFFERED_SERVICES_INFO: + VSOMEIP_WARNING << "BLOCKING CALL OFFERED_SERVICES_INFO(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + break; + case handler_type_e::WATCHDOG: + VSOMEIP_WARNING << "BLOCKING CALL WATCHDOG(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + break; + case handler_type_e::UNKNOWN: + VSOMEIP_WARNING << "BLOCKING CALL UNKNOWN(" + << std::hex << std::setw(4) << std::setfill('0') << get_client() << ")"; + break; + } +} + + +void application_impl::get_offered_services_async(offer_type_e _offer_type, + const offered_services_handler_t &_handler) { + { + std::lock_guard<std::mutex> its_lock(offered_services_handler_mutex_); + offered_services_handler_ = _handler; + } + + if (!is_routing_manager_host_) { + routing_->send_get_offered_services_info(get_client(), _offer_type); + } else { + std::vector<std::pair<service_t, instance_t>> its_services; + auto its_routing_manager_host = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + + for (const auto& s : its_routing_manager_host->get_offered_services()) { + for (const auto& i : s.second) { + auto its_unreliable_endpoint = i.second->get_endpoint(false); + auto its_reliable_endpoint = i.second->get_endpoint(true); + + if (_offer_type == offer_type_e::OT_LOCAL) { + if ( ((its_unreliable_endpoint && (its_unreliable_endpoint->get_local_port() == ILLEGAL_PORT)) + && (its_reliable_endpoint && (its_reliable_endpoint->get_local_port() == ILLEGAL_PORT))) + || (!its_reliable_endpoint && !its_unreliable_endpoint)) { + its_services.push_back(std::make_pair(s.first, i.first)); + } + } else if (_offer_type == offer_type_e::OT_REMOTE) { + if ((its_unreliable_endpoint && its_unreliable_endpoint->get_local_port() != ILLEGAL_PORT) + || (its_reliable_endpoint && its_reliable_endpoint->get_local_port() != ILLEGAL_PORT)) { + its_services.push_back(std::make_pair(s.first, i.first)); + } + } else if (_offer_type == offer_type_e::OT_ALL) { + its_services.push_back(std::make_pair(s.first, i.first)); + } + } + } + on_offered_services_info(its_services); + } + return; +} + + +void application_impl::on_offered_services_info(std::vector<std::pair<service_t, instance_t>> &_services) { + bool has_offered_services_handler(false); + offered_services_handler_t handler = nullptr; + { + std::lock_guard<std::mutex> its_lock(offered_services_handler_mutex_); + if (offered_services_handler_) { + has_offered_services_handler = true; + handler = offered_services_handler_; + } + } + if (has_offered_services_handler) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + auto its_sync_handler = std::make_shared<sync_handler>([handler, _services]() { + handler(_services); + }); + its_sync_handler->handler_type_ = handler_type_e::OFFERED_SERVICES_INFO; + handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); + } +} + +void application_impl::watchdog_cbk(boost::system::error_code const &_error) { + if (!_error) { + + watchdog_handler_t handler = nullptr; + { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + handler = watchdog_handler_; + if (handler && std::chrono::seconds::zero() != watchdog_interval_) { + watchdog_timer_.expires_from_now(watchdog_interval_); + watchdog_timer_.async_wait(std::bind(&application_impl::watchdog_cbk, + this, std::placeholders::_1)); + } + } + + if (handler) { + std::lock_guard<std::mutex> its_lock(handlers_mutex_); + auto its_sync_handler = std::make_shared<sync_handler>([handler]() { handler(); }); + its_sync_handler->handler_type_ = handler_type_e::WATCHDOG; + handlers_.push_back(its_sync_handler); + dispatcher_condition_.notify_one(); + } + } +} + +void application_impl::set_watchdog_handler(const watchdog_handler_t &_handler, + std::chrono::seconds _interval) { + if (_handler && std::chrono::seconds::zero() != _interval) { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + watchdog_handler_ = _handler; + watchdog_interval_ = _interval; + watchdog_timer_.expires_from_now(_interval); + watchdog_timer_.async_wait(std::bind(&application_impl::watchdog_cbk, + this, std::placeholders::_1)); + } else { + std::lock_guard<std::mutex> its_lock(watchdog_timer_mutex_); + watchdog_timer_.cancel(); + watchdog_handler_ = nullptr; + watchdog_interval_ = std::chrono::seconds::zero(); + } +} + +void application_impl::register_async_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const async_subscription_handler_t &_handler) { + + async_subscription_handler_ext_t its_handler_ext + = [_handler](client_t _client, uid_t _uid, gid_t _gid, + const std::string &_env, bool _is_subscribed, + const std::function< void (const bool) > &_cb) { + + (void)_env; // compatibility + _handler(_client, _uid, _gid, _is_subscribed, _cb); + }; + + register_async_subscription_handler(_service, _instance, _eventgroup, + its_handler_ext); +} + +void application_impl::register_async_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const async_subscription_handler_ext_t &_handler) { + + async_subscription_handler_sec_t its_handler_sec = [_handler]( + client_t _client, + const vsomeip_sec_client_t* _sec_client, + const std::string& _env, + bool _is_subscribed, + const std::function<void(bool)> &_cb + ){ + uid_t its_uid {_sec_client->user}; + gid_t its_gid {_sec_client->group}; + + _handler( + _client, + its_uid, + its_gid, + _env, + _is_subscribed, + _cb + ); + }; + + register_async_subscription_handler(_service, _instance, _eventgroup, its_handler_sec); +} + +void application_impl::register_async_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_sec_t _handler) { + + std::lock_guard<std::mutex> its_lock(subscription_mutex_); + subscription_[_service][_instance][_eventgroup] = std::make_pair(nullptr, _handler); +} + +void application_impl::register_sd_acceptance_handler( + const sd_acceptance_handler_t &_handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_sd_acceptance_handler(_handler); + } +} + +void application_impl::register_reboot_notification_handler( + const reboot_notification_handler_t &_handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_reboot_notification_handler(_handler); + } +} + +void application_impl::set_sd_acceptance_required( + const remote_info_t &_remote, const std::string &_path, bool _enable) { + + if (!is_routing()) { + return; + } + + const boost::asio::ip::address its_address(_remote.ip_.is_v4_ ? + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v4( + _remote.ip_.address_.v4_)) : + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v6( + _remote.ip_.address_.v6_))); + + if (_remote.first_ == std::numeric_limits<std::uint16_t>::max() + && _remote.last_ == 0) { + // special case to (de)activate rules per IP + configuration_->set_sd_acceptance_rules_active(its_address, _enable); + return; + } + + configuration::port_range_t its_range { _remote.first_, _remote.last_ }; + configuration_->set_sd_acceptance_rule(its_address, + its_range, port_type_e::PT_UNKNOWN, + _path, _remote.is_reliable_, _enable, true); + + if (_enable && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->sd_acceptance_enabled(its_address, its_range, + _remote.is_reliable_); + } +} + +void application_impl::set_sd_acceptance_required( + const sd_acceptance_map_type_t& _remotes, bool _enable) { + + (void)_remotes; + (void)_enable; + +#if 0 + if (!is_routing()) { + return; + } + + configuration::sd_acceptance_rules_t its_rules; + for (const auto& remote_info : _remotes) { + const boost::asio::ip::address its_address(remote_info.first.ip_.is_v4_ ? + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v4( + remote_info.first.ip_.address_.v4_)) : + static_cast<boost::asio::ip::address>(boost::asio::ip::address_v6( + remote_info.first.ip_.address_.v6_))); + const boost::icl::interval<std::uint16_t>::interval_type its_interval = + remote_info.first.is_range_ ? + boost::icl::interval<std::uint16_t>::closed( + remote_info.first.first_, + ((remote_info.first.last_ == ANY_PORT) ? + std::numeric_limits<std::uint16_t>::max() : + remote_info.first.last_)) : + boost::icl::interval<std::uint16_t>::closed( + remote_info.first.first_, remote_info.first.first_); + + const bool its_reliability = remote_info.first.is_reliable_; + + const auto found_address = its_rules.find(its_address); + if (found_address != its_rules.end()) { + const auto found_reliability = found_address->second.second.find( + its_reliability); + if (found_reliability != found_address->second.second.end()) { + found_reliability->second.insert(its_interval); + } else { + found_address->second.second.emplace(std::make_pair( + its_reliability, + boost::icl::interval_set<std::uint16_t>(its_interval))); + } + } else { + its_rules.insert(std::make_pair(its_address, + std::make_pair(remote_info.second, + std::map<bool, boost::icl::interval_set<std::uint16_t>>( + {{ its_reliability, + boost::icl::interval_set<std::uint16_t>( + its_interval) } })))); + } + } + + configuration_->set_sd_acceptance_rules(its_rules, _enable); +#endif +} + +application::sd_acceptance_map_type_t +application_impl::get_sd_acceptance_required() { + + sd_acceptance_map_type_t its_ret; + + if (is_routing()) { + for (const auto& e : configuration_->get_sd_acceptance_rules()) { + remote_info_t its_remote_info; + its_remote_info.ip_.is_v4_ = e.first.is_v4(); + if (its_remote_info.ip_.is_v4_) { + its_remote_info.ip_.address_.v4_ = e.first.to_v4().to_bytes(); + } else { + its_remote_info.ip_.address_.v6_ = e.first.to_v6().to_bytes(); + } + for (const auto& reliability : e.second.second) { + its_remote_info.is_reliable_ = reliability.first; + for (const auto& port_range : reliability.second.first) { + if (port_range.lower() == port_range.upper()) { + its_remote_info.first_ = port_range.lower(); + its_remote_info.last_ = port_range.lower(); + its_remote_info.is_range_ = false; + } else { + its_remote_info.first_ = port_range.lower(); + its_remote_info.last_ = port_range.upper(); + its_remote_info.is_range_ = true; + } + its_ret[its_remote_info] = e.second.first; + } + for (const auto& port_range : reliability.second.second) { + if (port_range.lower() == port_range.upper()) { + its_remote_info.first_ = port_range.lower(); + its_remote_info.last_ = port_range.lower(); + its_remote_info.is_range_ = false; + } else { + its_remote_info.first_ = port_range.lower(); + its_remote_info.last_ = port_range.upper(); + its_remote_info.is_range_ = true; + } + its_ret[its_remote_info] = e.second.first; + } + } + } + } + + return its_ret; +} + +void application_impl::register_routing_ready_handler( + const routing_ready_handler_t &_handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_routing_ready_handler(_handler); + } +} + +void application_impl::register_routing_state_handler( + const routing_state_handler_t &_handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_routing_state_handler(_handler); + } +} + +bool application_impl::update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer) { + bool ret = false; + if (!is_routing_manager_host_) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + if (_offer) { + ret = rm_impl->offer_service_remotely(_service, _instance, + _port, _reliable, _magic_cookies_enabled); + } else { + ret = rm_impl->stop_offer_service_remotely(_service, _instance, + _port, _reliable, _magic_cookies_enabled); + } + } + } + return ret; +} + +void application_impl::update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + ::std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + const security_update_handler_t &_handler) { +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_uid; + (void)_gid; + (void)_policy; + (void)_payload; + (void)_handler; +#else + if (!is_routing()) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + rm_impl->update_security_policy_configuration(_uid, _gid, _policy, _payload, _handler); + } + } +#endif // VSOMEIP_DISABLE_SECURITY +} + +void application_impl::remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + const security_update_handler_t &_handler) { +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_uid; + (void)_gid; + (void)_handler; +#else + if (!is_routing()) { + VSOMEIP_ERROR << __func__ << " is only intended to be called by " + "application acting as routing manager host"; + } else if (!routing_) { + VSOMEIP_ERROR << __func__ << " routing is zero"; + } else { + auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + if (rm_impl) { + rm_impl->remove_security_policy_configuration(_uid, _gid, _handler); + } + } +#endif // !VSOMEIP_DISABLE_SECURITY +} + +void application_impl::subscribe_with_debounce(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const debounce_filter_t &_filter) { + + if (routing_) { + bool send_back_cached(false); + bool send_back_cached_group(false); + check_send_back_cached_event(_service, _instance, _event, _eventgroup, + &send_back_cached, &send_back_cached_group); + + if (send_back_cached) { + send_back_cached_event(_service, _instance, _event); + } else if(send_back_cached_group) { + send_back_cached_eventgroup(_service, _instance, _eventgroup); + } + + if (check_subscription_state(_service, _instance, _eventgroup, _event)) { + + auto its_filter = std::make_shared<debounce_filter_impl_t>(_filter); + routing_->subscribe(client_, get_sec_client(), + _service, _instance, _eventgroup, _major, + _event, its_filter); + } + } +} + +bool +application_impl::is_local_endpoint(const boost::asio::ip::address &_unicast, + port_t _port) { + + try { + boost::asio::ip::tcp::endpoint its_endpoint(_unicast, _port); + boost::asio::ip::tcp::socket its_socket(io_, its_endpoint); + its_socket.close(); + + return true; + } catch (...) { + } + + return false; +} + +void application_impl::register_message_acceptance_handler( + const message_acceptance_handler_t &_handler) { + if (is_routing() && routing_) { + const auto rm_impl = std::dynamic_pointer_cast<routing_manager_impl>(routing_); + rm_impl->register_message_acceptance_handler(_handler); + } +} + +std::map<std::string, std::string> +application_impl::get_additional_data(const std::string &_plugin_name) { + if (configuration_) { + return configuration_->get_additional_data(name_, _plugin_name); + } + return std::map<std::string, std::string>(); +} + +void application_impl::register_message_handler_ext( + service_t _service, instance_t _instance, method_t _method, + const message_handler_t &_handler, + handler_registration_type_e _type) { + + const auto key = to_members_key(_service, _instance, _method); + + std::lock_guard<std::mutex> its_lock(members_mutex_); + switch (_type) { + case handler_registration_type_e::HRT_REPLACE: + members_[key].clear(); + [[gnu::fallthrough]]; + case handler_registration_type_e::HRT_APPEND: + members_[key].push_back(_handler); + break; + case handler_registration_type_e::HRT_PREPEND: + members_[key].push_front(_handler); + break; + default: + ; + } +} + +void application_impl::increment_active_threads() { + dispatcher_counter_++; + VSOMEIP_DEBUG << "Thread created. Number of active threads for " << name_ << " : " + << get_active_threads(); +} + +void application_impl::decrement_active_threads() { + dispatcher_counter_--; + VSOMEIP_DEBUG << "Thread destroyed. Number of active threads for " << name_ << " : " + << get_active_threads(); +} + +std::uint16_t application_impl::get_active_threads() const { + return dispatcher_counter_; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime.cpp new file mode 100644 index 00000000000..b9605f35856 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/runtime.hpp> + +#include "../include/runtime_impl.hpp" + +#include <mutex> + +namespace vsomeip_v3 { + +static std::mutex get_mutex_; + +std::string runtime::get_property(const std::string &_name) { + return runtime_impl::get_property(_name); +} + +void runtime::set_property(const std::string &_name, const std::string &_value) { + runtime_impl::set_property(_name, _value); +} + +std::shared_ptr<runtime> runtime::get() { + std::scoped_lock lk {get_mutex_}; + return runtime_impl::get(); +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime_impl.cpp new file mode 100644 index 00000000000..3886f7e223d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/runtime/src/runtime_impl.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/defines.hpp> + +#include "../include/application_impl.hpp" +#include "../include/runtime_impl.hpp" +#include "../../message/include/message_impl.hpp" +#include "../../message/include/payload_impl.hpp" + +namespace vsomeip_v3 { + +std::map<std::string, std::string> runtime_impl::properties_; + +std::string runtime_impl::get_property(const std::string &_name) { + auto found_property = properties_.find(_name); + if (found_property != properties_.end()) + return found_property->second; + return ""; +} + +void runtime_impl::set_property(const std::string &_name, const std::string &_value) { + properties_[_name] = _value; +} + +std::shared_ptr<runtime> runtime_impl::get() { + static std::shared_ptr<runtime> the_runtime_ = std::make_shared<runtime_impl>(); + return the_runtime_; +} + +std::shared_ptr<application> runtime_impl::create_application(const std::string& _name) { + + return create_application(_name, ""); +} + +std::shared_ptr<application> runtime_impl::create_application(const std::string& _name, + const std::string& _path) { + std::scoped_lock its_lock {applications_mutex_}; + static std::uint32_t postfix_id = 0; + std::string its_name = _name; + auto found_application = applications_.find(_name); + if (found_application != applications_.end()) { + its_name += "_" + std::to_string(postfix_id++); + } + std::shared_ptr<application> application = std::make_shared<application_impl>(its_name, _path); + applications_[its_name] = application; + return application; +} + +std::shared_ptr<message> runtime_impl::create_message(bool _reliable) const { + auto its_message = std::make_shared<message_impl>(); + its_message->set_protocol_version(VSOMEIP_PROTOCOL_VERSION); + its_message->set_return_code(return_code_e::E_OK); + its_message->set_reliable(_reliable); + its_message->set_interface_version(DEFAULT_MAJOR); + return its_message; +} + +std::shared_ptr<message> runtime_impl::create_request(bool _reliable) const { + auto its_request = std::make_shared<message_impl>(); + its_request->set_protocol_version(VSOMEIP_PROTOCOL_VERSION); + its_request->set_message_type(message_type_e::MT_REQUEST); + its_request->set_return_code(return_code_e::E_OK); + its_request->set_reliable(_reliable); + its_request->set_interface_version(DEFAULT_MAJOR); + return its_request; +} + +std::shared_ptr<message> runtime_impl::create_response( + const std::shared_ptr<message> &_request) const { + auto its_response = std::make_shared<message_impl>(); + its_response->set_service(_request->get_service()); + its_response->set_instance(_request->get_instance()); + its_response->set_method(_request->get_method()); + its_response->set_client(_request->get_client()); + its_response->set_session(_request->get_session()); + its_response->set_interface_version(_request->get_interface_version()); + its_response->set_message_type(message_type_e::MT_RESPONSE); + its_response->set_return_code(return_code_e::E_OK); + its_response->set_reliable(_request->is_reliable()); + return its_response; +} + +std::shared_ptr<message> runtime_impl::create_notification( + bool _reliable) const { + auto its_notification = std::make_shared<message_impl>(); + its_notification->set_protocol_version(VSOMEIP_PROTOCOL_VERSION); + its_notification->set_message_type(message_type_e::MT_NOTIFICATION); + its_notification->set_return_code(return_code_e::E_OK); + its_notification->set_reliable(_reliable); + its_notification->set_interface_version(DEFAULT_MAJOR); + return its_notification; +} + +std::shared_ptr<payload> runtime_impl::create_payload() const { + return std::make_shared<payload_impl>(); +} + +std::shared_ptr<payload> runtime_impl::create_payload(const byte_t *_data, + uint32_t _size) const { + return std::make_shared<payload_impl>(_data, _size); +} + +std::shared_ptr<payload> runtime_impl::create_payload( + const std::vector<byte_t> &_data) const { + return std::make_shared<payload_impl>(_data); +} + +std::shared_ptr<application> runtime_impl::get_application( + const std::string &_name) const { + std::scoped_lock its_lock {applications_mutex_}; + auto found_application = applications_.find(_name); + if(found_application != applications_.end()) + return found_application->second.lock(); + return nullptr; +} + +void runtime_impl::remove_application( + const std::string &_name) { + std::scoped_lock its_lock {applications_mutex_}; + auto found_application = applications_.find(_name); + if(found_application != applications_.end()) { + applications_.erase(_name); + } +} +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy.hpp new file mode 100644 index 00000000000..fd222430cb8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy.hpp @@ -0,0 +1,113 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_POLICY_HPP_ +#define VSOMEIP_V3_POLICY_HPP_ + +#include <cstring> +#include <map> +#include <mutex> +#include <utility> +#include <vector> + +#include <boost/icl/interval_map.hpp> +#include <boost/icl/interval_set.hpp> +#if defined(__QNX__) +#include <boost/icl/concept/interval_associator.hpp> +#endif + +#include <vsomeip/constants.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { + +template<typename T_> +void get_bounds(const boost::icl::discrete_interval<T_> &_interval, + T_ &_lower, T_ &_upper) { + + T_ its_lower, its_upper; + + its_lower = _interval.lower(); + its_upper = _interval.upper(); + + switch (_interval.bounds().bits()) { + case boost::icl::interval_bounds::static_open: + its_lower++; + its_upper--; + break; + case boost::icl::interval_bounds::static_left_open: + its_lower++; + break; + case boost::icl::interval_bounds::static_right_open: + its_upper--; + break; + default: + ; + } + + _lower = its_lower; + _upper = its_upper; +} + +struct policy { + policy() : allow_who_(false), allow_what_(false) {}; + + // Returns true if the policy is defined for single uid/gid pair. + // uid & gid are copied to the arguments. Otherwise, returns false. + bool get_uid_gid(uid_t &_uid, gid_t &_gid) const; + + bool deserialize_uid_gid(const byte_t * &_data, uint32_t &_size, + uid_t &_uid, gid_t &_gid) const; + bool deserialize(const byte_t * &_data, uint32_t &_size); + bool serialize(std::vector<byte_t> &_data) const; + + void print() const; + + // Members + boost::icl::interval_map<uid_t, + boost::icl::interval_set<gid_t> > credentials_; + bool allow_who_; + + boost::icl::interval_map<service_t, + boost::icl::interval_map<instance_t, + boost::icl::interval_set<method_t> > > requests_; + boost::icl::interval_map<service_t, + boost::icl::interval_set<instance_t> > offers_; + bool allow_what_; + + mutable std::mutex mutex_; + +private: + bool deserialize_ids(const byte_t * &_data, uint32_t &_size, + boost::icl::interval_map<uint16_t, + boost::icl::interval_set<uint16_t> > &_ids) const; + bool deserialize_id_item_list(const byte_t * &_data, uint32_t &_size, + boost::icl::interval_set<uint16_t> &_intervals) const; + bool deserialize_id_item(const byte_t * &_data, uint32_t &_size, + uint16_t &_low, uint16_t &_high) const; + + bool deserialize_u32(const byte_t * &_data, uint32_t &_size, + uint32_t &_value) const; + bool deserialize_u16(const byte_t * &_data, uint32_t &_size, + uint16_t &_value) const; + + bool serialize_uid_gid(std::vector<byte_t> &_data) const; + void serialize_interval_set( + const boost::icl::interval_set<uint16_t> &_intervals, + std::vector<byte_t> &_data) const; + void serialize_interval( + const boost::icl::discrete_interval<uint16_t> &_interval, + std::vector<byte_t> &_data) const; + + void serialize_u32(uint32_t _value, std::vector<byte_t> &_data) const; + void serialize_u32_at(uint32_t _value, std::vector<byte_t> &_data, + size_t _pos) const; + void serialize_u16(uint16_t _value, std::vector<byte_t> &_data) const; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_POLICY_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy_manager_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy_manager_impl.hpp new file mode 100644 index 00000000000..1b75a5a8dff --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/policy_manager_impl.hpp @@ -0,0 +1,195 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SECURITY_POLICY_MANAGER_IMPL_HPP_ +#define VSOMEIP_V3_SECURITY_POLICY_MANAGER_IMPL_HPP_ + +#include <map> +#include <mutex> +#include <unordered_set> +#include <vector> + +#include <boost/property_tree/ptree.hpp> +#include <boost/filesystem.hpp> +#include <boost/thread.hpp> + +#include <vsomeip/export.hpp> +#include <vsomeip/internal/policy_manager.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "../include/policy.hpp" + +namespace vsomeip_v3 { + +struct configuration_element; + +class VSOMEIP_IMPORT_EXPORT policy_manager_impl +#ifndef VSOMEIP_DISABLE_SECURITY + : public policy_manager +#endif // !VSOMEIP_DISABLE_SECURITY +{ +public: + enum class policy_loaded_e : std::uint8_t { + POLICY_PATH_FOUND_AND_LOADED = 0x0, + POLICY_PATH_FOUND_AND_NOT_LOADED = 0x1, + POLICY_PATH_INEXISTENT = 0x2 + }; + + policy_manager_impl(); + +#ifndef VSOMEIP_DISABLE_SECURITY + // policy_manager interface + std::shared_ptr<policy> create_policy() const; + void print_policy(const std::shared_ptr<policy> &_policy) const; + + bool parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size, + uid_t &_uid, gid_t &_gid) const; + bool parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size, + uid_t &_uid, gid_t &_gid, + const std::shared_ptr<policy> &_policy) const; + + bool is_policy_update_allowed(uid_t _uid, + std::shared_ptr<policy> &_policy) const; + bool is_policy_removal_allowed(uid_t _uid) const; + + // extension + void load(const configuration_element &_element, + const bool _lazy_load = false); + + void update_security_policy(uid_t _uid, uid_t _gid, const std::shared_ptr<policy>& _policy); + bool remove_security_policy(uid_t _uid, uid_t _gid); + + void add_security_credentials(uid_t _uid, uid_t _gid, + const std::shared_ptr<policy>& _credentials_policy, client_t _client); + + void get_requester_policies(const std::shared_ptr<policy> _policy, + std::set<std::shared_ptr<policy> > &_requesters) const; + void get_clients(uid_t _uid, gid_t _gid, std::unordered_set<client_t> &_clients) const; + + bool is_policy_extension(const std::string &_path) const; + std::string get_policy_extension_path(const std::string &_client_host) const; + + void set_policy_extension_base_path(const std::string &_path); + std::string get_security_config_folder(const std::string &its_folder) const; + std::string get_policy_extension_path_unlocked(const std::string &_client_host) const; + + policy_loaded_e is_policy_extension_loaded(const std::string &_client_host) const; + void set_is_policy_extension_loaded(const std::string &_client_host, const bool _loaded); + +private: + + // Configuration + bool exist_in_any_client_policies_unlocked(std::shared_ptr<policy> &_policy); + void load_policies(const configuration_element &_element); + void load_policy(const boost::property_tree::ptree &_tree); + void load_policy_body(std::shared_ptr<policy> &_policy, + const boost::property_tree::ptree::const_iterator &_tree); + void load_credential(const boost::property_tree::ptree &_tree, + boost::icl::interval_map<uid_t, boost::icl::interval_set<gid_t> > &_ids); + bool load_routing_credentials(const configuration_element &_element); + template<typename T_> + void load_interval_set(const boost::property_tree::ptree &_tree, + boost::icl::interval_set<T_> &_range, bool _exclude_margins = false); + void load_security_update_whitelist(const configuration_element &_element); + void load_security_policy_extensions(const configuration_element &_element); +#endif // !VSOMEIP_DISABLE_SECURITY + +public: + bool is_enabled() const; + bool is_audit() const; + + bool check_credentials(client_t _client, + const vsomeip_sec_client_t *_sec_client); + bool check_routing_credentials( + const vsomeip_sec_client_t *_sec_client) const; + void set_routing_credentials(uid_t _uid, gid_t _gid, + const std::string &_name); + + bool is_client_allowed(const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, method_t _method, + bool _is_request_service = false) const; + bool is_offer_allowed(const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance) const; + + bool get_sec_client_to_clients_mapping(const vsomeip_sec_client_t *_sec_client, + std::set<client_t> &_clients); + bool remove_client_to_sec_client_mapping(client_t _client); + + bool get_client_to_sec_client_mapping(client_t _client, vsomeip_sec_client_t &_sec_client); + bool store_client_to_sec_client_mapping(client_t _client, const vsomeip_sec_client_t *_sec_client); + void store_sec_client_to_client_mapping(const vsomeip_sec_client_t *_sec_client, client_t _client); + +private: +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4251) +#endif +#ifndef VSOMEIP_DISABLE_SECURITY + mutable boost::shared_mutex any_client_policies_mutex_; + std::vector<std::shared_ptr<policy> > any_client_policies_; + + mutable boost::shared_mutex is_client_allowed_cache_mutex_; + mutable std::map<std::pair<uid_t, gid_t>, + std::set<std::tuple<service_t, instance_t, method_t> > + > is_client_allowed_cache_; + + bool policy_enabled_; + bool check_credentials_; + bool allow_remote_clients_; + bool check_whitelist_; + + mutable std::mutex service_interface_whitelist_mutex_; + boost::icl::interval_set<service_t> service_interface_whitelist_; + + mutable std::mutex uid_whitelist_mutex_; + boost::icl::interval_set<uint32_t> uid_whitelist_; + + mutable std::mutex policy_base_path_mutex_; + std::string policy_base_path_; + + mutable boost::shared_mutex policy_extension_paths_mutex_; + //map[hostname, pair[path, map[complete path with UID/GID, control loading]] + std::map<std::string, std::pair<std::string, std::map<std::string, bool>>> policy_extension_paths_; + + bool check_routing_credentials_; +#endif // !VSOMEIP_DISABLE_SECURITY + + bool is_configured_; + + mutable std::mutex routing_credentials_mutex_; + std::pair<uint32_t, uint32_t> routing_credentials_; + + mutable std::mutex ids_mutex_; + std::map<client_t, vsomeip_sec_client_t> ids_; + + struct vsomeip_sec_client_comparator_t { + bool operator()(const vsomeip_sec_client_t &_lhs, const vsomeip_sec_client_t &_rhs) const { + if (_lhs.port < _rhs.port) { + return true; + } else if (_lhs.port == _rhs.port) { + if (_lhs.port == VSOMEIP_SEC_PORT_UNUSED) { + return ((_lhs.user < _rhs.user) + || ((_lhs.user == _rhs.user) + && (_lhs.group < _rhs.group))); + } else { + return ((_lhs.host < _rhs.host) + || ((_lhs.host == _rhs.host) + && (_lhs.port < _rhs.port))); + } + } + return false; + } + }; + + mutable std::mutex sec_client_to_clients_mutex_; + std::map<vsomeip_sec_client_t, std::set<client_t>, vsomeip_sec_client_comparator_t> sec_client_to_clients_; +#ifdef _WIN32 +#pragma warning(pop) +#endif +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SECURITY_POLICY_MANAGER_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/security.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/security.hpp new file mode 100644 index 00000000000..5736776fd1e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/include/security.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SECURITY_HPP_ +#define VSOMEIP_V3_SECURITY_HPP_ + +#include <functional> +#include <memory> + +#include <vsomeip/export.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "policy_manager_impl.hpp" + +namespace vsomeip_v3 { + +class VSOMEIP_IMPORT_EXPORT security { +public: + security(std::shared_ptr<policy_manager_impl> _policy_manager); + bool load(); + + std::function<decltype(vsomeip_sec_policy_initialize)> initialize; + std::function<decltype(vsomeip_sec_policy_authenticate_router)> authenticate_router; + std::function<decltype(vsomeip_sec_policy_is_client_allowed_to_offer)> is_client_allowed_to_offer; + std::function<decltype(vsomeip_sec_policy_is_client_allowed_to_request)> is_client_allowed_to_request; + std::function<decltype(vsomeip_sec_policy_is_client_allowed_to_access_member)> is_client_allowed_to_access_member; + std::function<decltype(vsomeip_sec_sync_client)> sync_client; + +private: + + decltype(vsomeip_sec_policy_initialize) default_initialize; + decltype(vsomeip_sec_policy_authenticate_router) default_authenticate_router; + decltype(vsomeip_sec_policy_is_client_allowed_to_offer) default_is_client_allowed_to_offer; + decltype(vsomeip_sec_policy_is_client_allowed_to_request) default_is_client_allowed_to_request; + decltype(vsomeip_sec_policy_is_client_allowed_to_access_member) default_is_client_allowed_to_access_member; + decltype(vsomeip_sec_sync_client) default_sync_client; + + std::shared_ptr<policy_manager_impl> policy_manager_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SECURITY_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy.cpp new file mode 100644 index 00000000000..afe84691bc0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy.cpp @@ -0,0 +1,507 @@ +// Copyright (C) 2020-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if __GNUC__ > 11 +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/policy.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { + +bool +policy::get_uid_gid(uid_t &_uid, gid_t &_gid) const { + + if (credentials_.size() != 1) + return false; + + const auto its_uids = credentials_.begin()->first; + const auto its_gids = credentials_.begin()->second; + + if (its_gids.size() != 1) + return false; + + if (its_uids.lower() != its_uids.upper() + || its_gids.begin()->lower() != its_gids.begin()->upper()) + return false; + + _uid = its_uids.lower(); + _gid = its_gids.begin()->lower(); + + return true; +} + +bool +policy::deserialize_uid_gid(const byte_t * &_data, uint32_t &_size, + uid_t &_uid, gid_t &_gid) const { + + bool its_result; + + uint32_t raw_uid; + its_result = deserialize_u32(_data, _size, raw_uid); + if (its_result) + _uid = static_cast<uid_t>(raw_uid); + else + return false; + + uint32_t raw_gid; + its_result = deserialize_u32(_data, _size, raw_gid); + if (its_result) + _gid = static_cast<gid_t>(raw_gid); + else + return false; + + return true; +} + +bool +policy::deserialize(const byte_t * &_data, uint32_t &_size) { + + bool its_result; + uid_t its_uid; + gid_t its_gid; + + std::lock_guard<std::mutex> its_lock(mutex_); + + its_result = deserialize_uid_gid(_data, _size, its_uid, its_gid); + if (its_result == false) + return false; + + // Fill policy uid/gid + const auto its_uid_interval + = boost::icl::interval<uid_t>::closed(its_uid, its_uid); + boost::icl::interval_set<gid_t> its_gid_set; + its_gid_set.insert(its_gid); + credentials_ += std::make_pair(its_uid_interval, its_gid_set); + + // Deserialized policies are always "Allow" - policies + allow_who_ = true; + allow_what_ = true; + + // Deserialize requests array length + uint32_t its_requests_length; + its_result = deserialize_u32(_data, _size, its_requests_length); + if (its_result == false) + return false; + + // Deserialize requests + while (0 < its_requests_length) { + + uint32_t its_current_size(_size); + + uint16_t its_service; + its_result = deserialize_u16(_data, _size, its_service); + if (its_result == false) + return false; + + if (its_service == 0x0000 || its_service == 0xffff) { + VSOMEIP_WARNING << "vSomeIP Security: Policy with service ID: 0x" + << std::hex << its_service << " is not allowed!"; + return false; + } + + const auto its_service_interval + = boost::icl::interval<service_t>::closed(its_service, its_service); + + boost::icl::interval_map<instance_t, + boost::icl::interval_set<method_t> > its_ids; + its_result = deserialize_ids(_data, _size, its_ids); + if (its_result == false) + return false; + + requests_ += std::make_pair(its_service_interval, its_ids); + + its_requests_length -= (its_current_size - _size); + } + + // Deserialize offers array length + uint32_t its_offers_length; + its_result = deserialize_u32(_data, _size, its_offers_length); + if (its_result == false) + return false; + + while (0 < its_offers_length) { + + uint32_t its_current_size(_size); + + uint16_t its_service; + its_result = deserialize_u16(_data, _size, its_service); + if (its_result == false) + return false; + + if (its_service == 0x0000 || its_service == 0xFFFF) { + VSOMEIP_WARNING << "vSomeIP Security: Policy with service ID: 0x" + << std::hex << its_service << " is not allowed!"; + return false; + } + + const auto its_service_interval + = boost::icl::interval<service_t>::closed(its_service, its_service); + + boost::icl::interval_set<instance_t> its_instance_interval_set; + its_result = deserialize_id_item_list(_data, _size, + its_instance_interval_set); + if (its_result == false) + return false; + + offers_ += std::make_pair(its_service_interval, its_instance_interval_set); + + its_offers_length -= (its_current_size - _size); + } + + return true; +} + +bool +policy::deserialize_ids(const byte_t * &_data, uint32_t &_size, + boost::icl::interval_map<uint16_t, + boost::icl::interval_set<uint16_t> > &_ids) const { + + boost::icl::interval_map<uint16_t, + boost::icl::interval_set<uint16_t> > its_ids; + uint32_t its_array_length; + bool its_result; + + its_result = deserialize_u32(_data, _size, its_array_length); + if (its_result == false) + return false; + + while (0 < its_array_length) { + uint32_t its_current_size(_size); + + boost::icl::interval_set<uint16_t> its_instances, its_methods; + its_result = deserialize_id_item_list(_data, _size, its_instances); + if (its_result == false) + return false; + + its_result = deserialize_id_item_list(_data, _size, its_methods); + if (its_result == false) + return false; + + for (const auto& i : its_instances) + its_ids += std::make_pair(i, its_methods); + + its_array_length -= (its_current_size - _size); + } + + _ids = std::move(its_ids); + + return true; +} + +bool +policy::deserialize_id_item_list(const byte_t * &_data, uint32_t &_size, + boost::icl::interval_set<uint16_t> &_intervals) const { + + boost::icl::interval_set<uint16_t> its_intervals; + uint32_t its_length; + bool its_result; + + its_result = deserialize_u32(_data, _size, its_length); + if (its_result == false) + return its_result; + + while (0 < its_length) { + + uint32_t its_current_size(_size); + + uint16_t its_low = 0; + uint16_t its_high = 0; + its_result = deserialize_id_item(_data, _size, its_low, its_high); + if (its_result == false) + return false; + + its_intervals.insert(boost::icl::interval<uint16_t>::closed(its_low, its_high)); + + its_length -= (its_current_size - _size); + } + + _intervals = std::move(its_intervals); + + return true; +} + +bool +policy::deserialize_id_item(const byte_t * &_data, uint32_t &_size, + uint16_t &_low, uint16_t &_high) const { + + uint32_t its_length, its_type; + bool its_result; + + its_result = deserialize_u32(_data, _size, its_length); + if (its_result == false) + return false; + + its_result = deserialize_u32(_data, _size, its_type); + if (its_result == false) + return false; + + if (its_type == 1 && its_length == sizeof(uint16_t)) { + its_result = deserialize_u16(_data, _size, _low); + if (its_result == false) + return false; + + _high = _low; + } else if (its_type == 2 + && its_length == sizeof(uint16_t) + sizeof(uint16_t)) { + its_result = deserialize_u16(_data, _size, _low); + if (its_result == false) + return false; + + its_result = deserialize_u16(_data, _size, _high); + if (its_result == false) + return false; + + if (_low > _high) + return false; + } + + // handle ANY_METHOD configuration + if (_low == ANY_METHOD && _high == ANY_METHOD) { + _low = 0x01; + } + + return (_low != 0x0000); +} + +bool +policy::deserialize_u16(const byte_t * &_data, uint32_t &_size, + uint16_t &_value) const { + + if (_size < sizeof(uint16_t)) + return false; + + _value = bithelper::read_uint16_be(_data); + + _data += sizeof(uint16_t); + _size -= static_cast<uint16_t>(sizeof(uint16_t)); + + return true; +} + +bool +policy::deserialize_u32(const byte_t * &_data, uint32_t &_size, + uint32_t &_value) const { + + if (_size < sizeof(uint32_t)) + return false; + + _value = bithelper::read_uint32_be(_data); + + _data += sizeof(uint32_t); + _size -= static_cast<uint32_t>(sizeof(uint32_t)); + + return true; +} + +bool +policy::serialize(std::vector<byte_t> &_data) const { + + bool its_result; + + std::lock_guard<std::mutex> its_lock(mutex_); + + its_result = serialize_uid_gid(_data); + if (!its_result) + return false; + + size_t its_requests_pos = _data.size(); + uint32_t its_requests_size(0); + serialize_u32(its_requests_size, _data); + + for (const auto &its_request : requests_) { + for (auto its_service = its_request.first.lower(); + its_service <= its_request.first.upper(); + its_service++) { + + serialize_u16(its_service, _data); + + size_t its_pos = _data.size(); + uint32_t its_instances_size(0); + serialize_u32(its_instances_size, _data); + + for (const auto &i : its_request.second) { + boost::icl::interval_set<instance_t> its_instances; + its_instances.insert(i.first); + serialize_interval_set(its_instances, _data); + serialize_interval_set(i.second, _data); + } + + its_instances_size = static_cast<uint32_t>(_data.size() - its_pos - sizeof(uint32_t)); + serialize_u32_at(its_instances_size, _data, its_pos); + } + } + + its_requests_size = static_cast<uint32_t>(_data.size() - its_requests_pos - sizeof(uint32_t)); + serialize_u32_at(its_requests_size, _data, its_requests_pos); + + uint32_t its_offers_size = 0; + serialize_u32(its_offers_size, _data); + + return true; +} + +bool +policy::serialize_uid_gid(std::vector<byte_t> &_data) const { + + if (credentials_.size() != 1) { + VSOMEIP_ERROR << "Unserializable policy (ids)."; + return false; + } + + auto its_credential = *(credentials_.begin()); + if (its_credential.second.size() != 1) { + VSOMEIP_ERROR << "Unserializable policy (intervals)."; + return false; + } + + auto its_uid_interval = its_credential.first; + if (its_uid_interval.lower() != its_uid_interval.upper()) { + VSOMEIP_ERROR << "Unserializable policy (uid)."; + return false; + } + + auto its_gid_interval = *(its_credential.second.begin()); + if (its_gid_interval.lower() != its_gid_interval.upper()) { + VSOMEIP_ERROR << "Unserializable policy (gid)."; + return false; + } + + serialize_u32(its_uid_interval.lower(), _data); + serialize_u32(its_gid_interval.lower(), _data); + + return true; +} + +void +policy::serialize_interval_set( + const boost::icl::interval_set<uint16_t> &_intervals, + std::vector<byte_t> &_data) const { + + size_t its_pos(_data.size()); + uint32_t its_interval_set_size(0); + serialize_u32(its_interval_set_size, _data); + + for (const auto& i : _intervals) + serialize_interval(i, _data); + + its_interval_set_size = static_cast<uint32_t>(_data.size() + - its_pos - sizeof(uint32_t)); + serialize_u32_at(its_interval_set_size, _data, its_pos); +} + +void +policy::serialize_interval( + const boost::icl::discrete_interval<uint16_t> &_interval, + std::vector<byte_t> &_data) const { + + uint32_t its_union_length, its_union_type; + + if (_interval.lower() == _interval.upper()) { // single value + its_union_length = static_cast<uint32_t>(sizeof(uint16_t)); + its_union_type = 1; + + serialize_u32(its_union_length, _data); + serialize_u32(its_union_type, _data); + + serialize_u16(_interval.lower(), _data); + } else { // value interval + its_union_type = 2; + its_union_length = static_cast<uint32_t>( + sizeof(uint16_t) + sizeof(uint16_t)); + + serialize_u32(its_union_length, _data); + serialize_u32(its_union_type, _data); + + serialize_u16(_interval.lower(), _data); + serialize_u16(_interval.upper(), _data); + } +} + +void +policy::serialize_u16(uint16_t _value, + std::vector<byte_t> &_data) const { + + uint8_t new_buffer[2] = {0}; + bithelper::write_uint16_be(_value, new_buffer); + _data.insert(_data.end(), new_buffer, new_buffer + sizeof(new_buffer)); +} + +void +policy::serialize_u32(uint32_t _value, + std::vector<byte_t> &_data) const { + + uint8_t new_buffer[4] = {0}; + bithelper::write_uint32_be(_value, new_buffer); + _data.insert(_data.end(), new_buffer, new_buffer + sizeof(new_buffer)); +} + +void +policy::serialize_u32_at(uint32_t _value, + std::vector<byte_t> &_data, size_t _pos) const { + + bithelper::write_uint32_be(_value, &_data[_pos]); +} + +void +policy::print() const { + + for (auto its_credential : credentials_) { + auto its_uid_interval = its_credential.first; + if (its_uid_interval.lower() == std::numeric_limits<uint32_t>::max()) { + VSOMEIP_INFO << "policy::print Security configuration: UID: any"; + } else { + VSOMEIP_INFO << "policy::print Security configuration: UID: " + << std::dec << its_uid_interval.lower(); + } + for (auto its_gid_interval : its_credential.second) { + if (its_gid_interval.lower() == std::numeric_limits<uint32_t>::max()) { + VSOMEIP_INFO << " policy::print Security configuration: GID: any"; + } else { + VSOMEIP_INFO << " policy::print Security configuration: GID: " + << std::dec << its_gid_interval.lower(); + } + } + } + + VSOMEIP_INFO << "policy::print Security configuration: REQUESTS POLICY SIZE: " + << std::dec << requests_.size(); + for (auto its_request : requests_) { + VSOMEIP_INFO << "policy::print ALLOWED REQUESTS Services:" + << std::hex << its_request.first; + for (auto its_instance : its_request.second) { + VSOMEIP_INFO << "policy::print Instances: "; + VSOMEIP_INFO << "policy::print first: 0x" + << std::hex << its_instance.first.lower() + << " last: 0x" << its_instance.first.upper(); + VSOMEIP_INFO << "policy::print Methods: "; + for (auto its_method : its_instance.second) { + VSOMEIP_INFO << "policy::print first: 0x" + << std::hex << its_method.lower() + << " last: 0x" << its_method.upper(); + } + } + } + + VSOMEIP_INFO << "policy::print Security configuration: OFFER POLICY SIZE: " + << std::dec << offers_.size(); + for (auto its_offer : offers_) { + VSOMEIP_INFO << "policy::print ALLOWED OFFERS Services:" + << std::hex << its_offer.first; + for (auto its_instance : its_offer.second) { + VSOMEIP_INFO << "policy::print Instances: "; + VSOMEIP_INFO << "policy::print first: 0x" + << std::hex << its_instance.lower() + << " last: 0x" << its_instance.upper(); + } + } +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy_manager_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy_manager_impl.cpp new file mode 100644 index 00000000000..e518d27ba3d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/policy_manager_impl.cpp @@ -0,0 +1,1450 @@ +// Copyright (C) 2019-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #define NOMINMAX + #include <windows.h> + #include <stdlib.h> +#endif + +#include <algorithm> +#include <sstream> + +#include "../include/policy_manager_impl.hpp" +#include "../../configuration/include/configuration_element.hpp" +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +template<typename T_> +void read_data(const std::string &_in, T_ &_out) { + std::stringstream its_converter; + + if (_in.size() > 2 + && _in[0] == '0' + && (_in[1] == 'x' || _in[1] == 'X')) + its_converter << std::hex << _in; + else + its_converter << std::dec << _in; + + its_converter >> _out; +} + +policy_manager_impl::policy_manager_impl() + : +#ifndef VSOMEIP_DISABLE_SECURITY + policy_enabled_(false), + check_credentials_(false), + allow_remote_clients_(true), + check_whitelist_(false), + policy_base_path_(""), + check_routing_credentials_(false), +#endif // !VSOMEIP_DISABLE_SECURITY + is_configured_(false) +{ +} + +bool +policy_manager_impl::is_enabled() const { +#ifdef VSOMEIP_DISABLE_SECURITY + return false; +#else + return policy_enabled_; +#endif +} + +bool +policy_manager_impl::is_audit() const { +#ifdef VSOMEIP_DISABLE_SECURITY + return false; +#else + return !check_credentials_; +#endif +} + +bool +policy_manager_impl::check_credentials(client_t _client, + const vsomeip_sec_client_t *_sec_client) { + +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_client; + (void)_sec_client; + + return true; +#else + if (!policy_enabled_) + return true; + + if (!_sec_client) + return true; + + if (_sec_client->port != VSOMEIP_SEC_PORT_UNUSED) + return true; + + uid_t its_uid(_sec_client->user); + gid_t its_gid(_sec_client->group); + + bool has_id(false); + + boost::shared_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + for (const auto &p : any_client_policies_) { + + std::lock_guard<std::mutex> its_policy_lock(p->mutex_); + + bool has_uid, has_gid(false); + + const auto found_uid = p->credentials_.find(its_uid); + has_uid = (found_uid != p->credentials_.end()); + if (has_uid) { + const auto found_gid = found_uid->second.find(its_gid); + has_gid = (found_gid != found_uid->second.end()); + } + + has_id = (has_uid && has_gid); + + if ((has_id && p->allow_who_) || (!has_id && !p->allow_who_)) { + // Code is unaccessible due to logic checks. + if (!store_client_to_sec_client_mapping(_client, _sec_client)) { + std::string security_mode_text = "!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << its_uid << "/" << its_gid + << " : Check credentials failed as existing credentials would be overwritten" + << security_mode_text; + return !check_credentials_; + } + store_sec_client_to_client_mapping(_sec_client, _client); + return true; + } + } + + std::string security_mode_text = " ~> Skip!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client + << " with UID/GID=" << std::dec << its_uid << "/" << its_gid + << " : Check credentials failed" << security_mode_text; + + return !check_credentials_; +#endif // VSOMEIP_DISABLE_SECURITY +} + +bool +policy_manager_impl::check_routing_credentials( + const vsomeip_sec_client_t *_sec_client) const { + +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_sec_client; + + return true; +#else + uid_t its_uid(0); + gid_t its_gid(0); + bool is_known_uid_gid(false); + + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + if (_sec_client && _sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + its_uid = _sec_client->user; + its_gid = _sec_client->group; + + if (routing_credentials_.first == its_uid + && routing_credentials_.second == its_gid) { + + return true; + } + + is_known_uid_gid = true; + } + + std::string security_mode_text = "!"; + if (!check_routing_credentials_) { + + security_mode_text = " but will be allowed due to audit mode is active!"; + } + + VSOMEIP_INFO << "vSomeIP Security: UID/GID=" + << (is_known_uid_gid ? std::to_string(its_uid) : "n/a") + << "." + << (is_known_uid_gid ? std::to_string(its_gid) : "n/a") + << " : Check routing credentials failed as " + << "configured routing manager credentials " + << "do not match with routing manager credentials" + << security_mode_text; + + return !check_routing_credentials_; +#endif // VSOMEIP_DISABLE_SECURITY +} + +void +policy_manager_impl::set_routing_credentials(uid_t _uid, gid_t _gid, + const std::string &_name) { + + if (is_configured_) { + VSOMEIP_WARNING << "vSomeIP Security: Multiple definitions of routing-credentials." + << " Ignoring definition from " << _name; + } else { + routing_credentials_ = std::make_pair(_uid, _gid); + is_configured_ = true; + } +} + +bool +policy_manager_impl::is_client_allowed(const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance, method_t _method, + bool _is_request_service) const { + +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_sec_client; + (void)_service; + (void)_instance; + (void)_method; + (void)_is_request_service; + + return true; +#else + if (!policy_enabled_) { + return true; + } + + uid_t its_uid(ANY_UID); + gid_t its_gid(ANY_GID); + if (_sec_client) { + if (_sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + its_uid = _sec_client->user; + its_gid = _sec_client->group; + } else { + return true; + } + } else { + std::string security_mode_text = " ~> Skip!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + VSOMEIP_INFO << "vSomeIP Security: uid/gid " + << std::dec << its_uid << "/" << its_gid << " is not valid." + << "Therefore it isn't allowed to communicate to service/instance " + << _service << "/" << _instance + << security_mode_text; + + return !check_credentials_; + } + + // Check cache + auto its_credentials = std::make_pair(its_uid, its_gid); + auto its_key = std::make_tuple(_service, _instance, _method); + { + boost::shared_lock<boost::shared_mutex> its_cache_lock(is_client_allowed_cache_mutex_); + const auto its_iter = is_client_allowed_cache_.find(its_credentials); + if (its_iter != is_client_allowed_cache_.end()) { + if (its_iter->second.find(its_key) != its_iter->second.end()) { + return true; + } + } + } + + + // Check policies + boost::shared_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + for (const auto &p : any_client_policies_) { + std::lock_guard<std::mutex> its_policy_lock(p->mutex_); + bool has_uid, has_gid(false); + bool is_matching(false); + + const auto found_uid = p->credentials_.find(its_uid); + has_uid = (found_uid != p->credentials_.end()); + if (has_uid) { + const auto found_gid = found_uid->second.find(its_gid); + has_gid = (found_gid != found_uid->second.end()); + } + + const auto found_service = p->requests_.find(_service); + if (found_service != p->requests_.end()) { + const auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (!_is_request_service) { + const auto found_method = found_instance->second.find(_method); + is_matching = (found_method != found_instance->second.end()); + } else { + // handle VSOMEIP_REQUEST_SERVICE + is_matching = true; + } + } + } + + if ((has_uid && has_gid && p->allow_who_) || ((!has_uid || !has_gid) && !p->allow_who_)) { + if (p->allow_what_) { + // allow policy + if (is_matching) { + boost::unique_lock<boost::shared_mutex> its_cache_lock(is_client_allowed_cache_mutex_); + is_client_allowed_cache_[its_credentials].insert(its_key); + return true; + } + } else { + // deny policy + // allow client if the service / instance / !ANY_METHOD was not found + if ((!is_matching && (_method != ANY_METHOD)) + // allow client if the service / instance / ANY_METHOD was not found + // and it is a "deny nothing" policy + || (!is_matching && (_method == ANY_METHOD) && p->requests_.empty())) { + boost::unique_lock<boost::shared_mutex> its_cache_lock(is_client_allowed_cache_mutex_); + is_client_allowed_cache_[its_credentials].insert(its_key); + return true; + } + } + } + } + + std::string security_mode_text = " ~> Skip!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + + VSOMEIP_INFO << "vSomeIP Security: UID/GID=" + << std::dec << its_uid << "/" << its_gid + << " : Isn't allowed to communicate with service/instance/(method / event) " + << std::hex << _service << "/" << _instance << "/" << _method + << security_mode_text; + + return !check_credentials_; +#endif // VSOMEIP_DISABLE_SECURITY +} + +bool +policy_manager_impl::is_offer_allowed(const vsomeip_sec_client_t *_sec_client, + service_t _service, instance_t _instance) const { + +#ifdef VSOMEIP_DISABLE_SECURITY + (void)_sec_client; + (void)_service; + (void)_instance; + + return true; +#else + if (!policy_enabled_) + return true; + + uint32_t its_uid(ANY_UID), its_gid(ANY_GID); + if (_sec_client) { + if (_sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + its_uid = _sec_client->user; + its_gid = _sec_client->group; + } else { + return true; + } + } else { + std::string security_mode_text = " ~> Skip offer!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + VSOMEIP_INFO << "vSomeIP Security: uid/gid " + << std::dec << its_uid << "/" << its_gid << " is not valid." + << "Therefore it isn't allowed to offer service/instance " + << _service << "/" << _instance + << security_mode_text; + + return !check_credentials_; + } + + boost::shared_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + for (const auto &p : any_client_policies_) { + std::lock_guard<std::mutex> its_policy_lock(p->mutex_); + bool has_uid, has_gid(false), has_offer(false); + + const auto found_uid = p->credentials_.find(its_uid); + has_uid = (found_uid != p->credentials_.end()); + if (has_uid) { + const auto found_gid = found_uid->second.find(its_gid); + has_gid = (found_gid != found_uid->second.end()); + } + + const auto found_service = p->offers_.find(_service); + if (found_service != p->offers_.end()) { + const auto found_instance = found_service->second.find(_instance); + has_offer = (found_instance != found_service->second.end()); + } + + if ((has_uid && has_gid && p->allow_who_) + || ((!has_uid || !has_gid) && !p->allow_who_)) { + if (p->allow_what_ == has_offer) { + return true; + } + } + } + + std::string security_mode_text = " ~> Skip offer!"; + if (!check_credentials_) { + security_mode_text = " but will be allowed due to audit mode is active!"; + } + + VSOMEIP_INFO << "vSomeIP Security: UID/GID=" + << std::dec << its_uid << "/" << its_gid + << " isn't allowed to offer service/instance " + << std::hex << _service << "/" << _instance + << security_mode_text; + + return !check_credentials_; +#endif // VSOMEIP_DISABLE_SECURITY +} + +#ifndef VSOMEIP_DISABLE_SECURITY +void +policy_manager_impl::load(const configuration_element &_element, const bool _lazy_load) { + + load_policies(_element); + if (!_lazy_load) { + + load_security_update_whitelist(_element); + load_security_policy_extensions(_element); + load_routing_credentials(_element); + + if (policy_enabled_ && check_credentials_) + VSOMEIP_INFO << "Security configuration is active."; + + if (policy_enabled_ && !check_credentials_) + VSOMEIP_INFO << "Security configuration is active but in audit mode (allow all)"; + } +} + +bool +policy_manager_impl::remove_security_policy(uid_t _uid, gid_t _gid) { + boost::unique_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + bool was_removed(false); + if (!any_client_policies_.empty()) { + std::vector<std::shared_ptr<policy>>::iterator p_it = any_client_policies_.begin(); + while (p_it != any_client_policies_.end()) { + bool is_matching(false); + { + std::lock_guard<std::mutex> its_policy_lock((*p_it)->mutex_); + bool has_uid(false), has_gid(false); + const auto found_uid = (*p_it)->credentials_.find(_uid); + has_uid = (found_uid != (*p_it)->credentials_.end()); + if (has_uid) { + const auto found_gid = found_uid->second.find(_gid); + has_gid = (found_gid != found_uid->second.end()); + } + + // only remove "credentials allow" policies to prevent removal of + // blacklist configured in file + if (has_uid && has_gid && (*p_it)->allow_who_) { + is_matching = true; + } + } + if (is_matching) { + was_removed = true; + p_it = any_client_policies_.erase(p_it); + } else { + ++p_it; + } + + boost::unique_lock<boost::shared_mutex> its_cache_lock(is_client_allowed_cache_mutex_); + is_client_allowed_cache_.erase(std::make_pair(_uid, _gid)); + } + } + return was_removed; +} + +void +policy_manager_impl::update_security_policy(uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy) { + + boost::unique_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + std::shared_ptr<policy> its_matching_policy; + for (auto p : any_client_policies_) { + std::lock_guard<std::mutex> its_guard(p->mutex_); + if (p->credentials_.size() == 1) { + const auto its_uids = *(p->credentials_.begin()); + if (its_uids.first.lower() == _uid + && its_uids.first.upper() == _uid) { + if (its_uids.second.size() == 1) { + const auto its_gids = *(its_uids.second.begin()); + if (its_gids.lower() == _gid + && its_gids.upper() == _gid) { + if (p->allow_who_ == _policy->allow_who_) { + its_matching_policy = p; + break; + } + } + } + } + } + } + + if (its_matching_policy) { + std::lock_guard<std::mutex> its_guard{its_matching_policy->mutex_}; + for (const auto &r : _policy->requests_) { + service_t its_lower, its_upper; + get_bounds(r.first, its_lower, its_upper); + for (auto s = its_lower; s <= its_upper; s++) { + boost::icl::discrete_interval<service_t> its_service(s, s, + boost::icl::interval_bounds::closed()); + its_matching_policy->requests_ += std::make_pair(its_service, r.second); + } + } + for (const auto &o : _policy->offers_) { + service_t its_lower, its_upper; + get_bounds(o.first, its_lower, its_upper); + for (auto s = its_lower; s <= its_upper; s++) { + boost::icl::discrete_interval<service_t> its_service(s, s, + boost::icl::interval_bounds::closed()); + its_matching_policy->offers_ += std::make_pair(its_service, o.second); + } + } + } else { + any_client_policies_.push_back(_policy); + } + + boost::unique_lock<boost::shared_mutex> its_cache_lock(is_client_allowed_cache_mutex_); + is_client_allowed_cache_.erase(std::make_pair(_uid, _gid)); +} + +void +policy_manager_impl::add_security_credentials(uid_t _uid, gid_t _gid, + const std::shared_ptr<policy> &_policy, client_t _client) { + + bool was_found(false); + boost::unique_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + for (const auto &p : any_client_policies_) { + bool has_uid(false), has_gid(false); + + std::lock_guard<std::mutex> its_policy_lock(p->mutex_); + const auto found_uid = p->credentials_.find(_uid); + has_uid = (found_uid != p->credentials_.end()); + if (has_uid) { + const auto found_gid = found_uid->second.find(_gid); + has_gid = (found_gid != found_uid->second.end()); + } + + if (has_uid && has_gid && p->allow_who_) { + was_found = true; + break; + } + } + + // Do not add the new (credentials-only-policy) if a allow + // credentials policy with same credentials was found + if (!was_found) { + any_client_policies_.push_back(_policy); + VSOMEIP_INFO << __func__ << " Added security credentials at client: 0x" + << std::hex << _client << std::dec << " with UID: " << _uid << " GID: " << _gid; + } +} + +bool +policy_manager_impl::is_policy_update_allowed(uid_t _uid, std::shared_ptr<policy> &_policy) const { + + bool is_uid_allowed(false); + { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + const auto found_uid = uid_whitelist_.find(_uid); + is_uid_allowed = (found_uid != uid_whitelist_.end()); + } + + if (is_uid_allowed && _policy) { + std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_); + std::lock_guard<std::mutex> its_policy_lock(_policy->mutex_); + for (const auto &its_request : _policy->requests_) { + bool has_service(false); + + service_t its_service(0); + for (its_service = its_request.first.lower(); + its_service <= its_request.first.upper(); + its_service++) { + + const auto found_service = service_interface_whitelist_.find(its_service); + has_service = (found_service != service_interface_whitelist_.end()); + if (!has_service) + break; + } + + if (!has_service) { + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy update requesting service ID: " + << std::hex << its_service + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy update requesting service ID: " + << std::hex << its_service + << " is not allowed! -> ignore update"; + } + return !check_whitelist_; + } + } + return true; + } else { + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy update for UID: " << std::dec << _uid + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy update for UID: " << std::dec << _uid + << " is not allowed! -> ignore update"; + } + return !check_whitelist_; + } +} + +bool +policy_manager_impl::is_policy_removal_allowed(uid_t _uid) const { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + for (auto its_uid_range : uid_whitelist_) { + if (its_uid_range.lower() <= _uid && _uid <= its_uid_range.upper()) { + return true; + } + } + + if (!check_whitelist_) { + VSOMEIP_INFO << "vSomeIP Security: Policy removal for UID: " + << std::dec << _uid + << " is not allowed, but will be allowed due to whitelist audit mode is active!"; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Policy removal for UID: " + << std::dec << _uid + << " is not allowed! -> ignore removal"; + } + return !check_whitelist_; +} + +bool +policy_manager_impl::parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size, + uid_t &_uid, gid_t &_gid, const std::shared_ptr<policy> &_policy) const { + + bool is_valid = _policy->deserialize(_buffer, _buffer_size); + if (is_valid) + is_valid = _policy->get_uid_gid(_uid, _gid); + return is_valid; +} + +/////////////////////////////////////////////////////////////////////////////// +// Configuration +/////////////////////////////////////////////////////////////////////////////// +bool +policy_manager_impl::exist_in_any_client_policies_unlocked(std::shared_ptr<policy> &_policy) { + for (const auto &p : any_client_policies_) { + std::lock_guard<std::mutex> its_policy_lock(p->mutex_); + if (p->credentials_ == _policy->credentials_ && + p->requests_ == _policy->requests_ && + p->offers_ == _policy->offers_ && + p->allow_what_ == _policy->allow_what_ && + p->allow_who_ == _policy->allow_who_) { + return true; + } + } + return false; +} + +void +policy_manager_impl::load_policies(const configuration_element &_element) { +#ifdef _WIN32 + return; +#endif + try { + auto optional = _element.tree_.get_child_optional("security"); + if (!optional) { + return; + } + policy_enabled_ = true; + auto found_policy = _element.tree_.get_child("security"); + for (auto its_security = found_policy.begin(); + its_security != found_policy.end(); ++its_security) { + if (its_security->first == "check_credentials") { + if (its_security->second.data() == "true") { + check_credentials_ = true; + } else { + check_credentials_ = false; + } + } else if (its_security->first == "allow_remote_clients") { + if (its_security->second.data() == "true") { + allow_remote_clients_ = true; + } else { + allow_remote_clients_ = false; + } + } else if (its_security->first == "policies") { + for (auto its_policy = its_security->second.begin(); + its_policy != its_security->second.end(); ++its_policy) { + load_policy(its_policy->second); + } + } + } + } catch (...) { + } +} + +void +policy_manager_impl::load_policy(const boost::property_tree::ptree &_tree) { + + std::shared_ptr<policy> policy(std::make_shared<policy>()); + bool allow_deny_set(false); + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + if (i->first == "credentials") { + boost::icl::interval_set<uid_t> its_uid_interval_set; + boost::icl::interval_set<gid_t> its_gid_interval_set; + boost::icl::discrete_interval<uid_t> its_uid_interval; + boost::icl::discrete_interval<gid_t> its_gid_interval; + + bool has_uid(false), has_gid(false); + bool has_uid_range(false), has_gid_range(false); + for (auto n = i->second.begin(); + n != i->second.end(); ++n) { + std::string its_key(n->first); + std::string its_value(n->second.data()); + if (its_key == "uid") { + if(n->second.data().empty()) { + load_interval_set(n->second, its_uid_interval_set); + has_uid_range = true; + } else { + if (its_value != "any") { + uint32_t its_uid; + read_data(its_value, its_uid); + its_uid_interval = boost::icl::construct< + boost::icl::discrete_interval<uid_t> >( + its_uid, its_uid, + boost::icl::interval_bounds::closed()); + } else { + its_uid_interval = boost::icl::construct< + boost::icl::discrete_interval<uid_t> >( + std::numeric_limits<uid_t>::min(), + std::numeric_limits<uid_t>::max(), + boost::icl::interval_bounds::closed()); + } + has_uid = true; + } + } else if (its_key == "gid") { + if(n->second.data().empty()) { + load_interval_set(n->second, its_gid_interval_set); + has_gid_range = true; + } else { + if (its_value != "any") { + uint32_t its_gid; + read_data(its_value, its_gid); + its_gid_interval = boost::icl::construct< + boost::icl::discrete_interval<gid_t> >( + its_gid, its_gid, + boost::icl::interval_bounds::closed()); + } else { + its_gid_interval = boost::icl::construct< + boost::icl::discrete_interval<gid_t> >( + std::numeric_limits<gid_t>::min(), + std::numeric_limits<gid_t>::max(), + boost::icl::interval_bounds::closed()); + } + has_gid = true; + } + } else if (its_key == "allow" || its_key == "deny") { + policy->allow_who_ = (its_key == "allow"); + load_credential(n->second, policy->credentials_); + } + } + + if (has_uid && has_gid) { + its_gid_interval_set.insert(its_gid_interval); + + policy->credentials_ += std::make_pair(its_uid_interval, its_gid_interval_set); + policy->allow_who_ = true; + } + if (has_uid_range && has_gid_range) { + for (const auto u : its_uid_interval_set) + policy->credentials_ += std::make_pair(u, its_gid_interval_set); + policy->allow_who_ = true; + } + } else if (i->first == "allow") { + if (allow_deny_set) { + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: \"allow\" tag overrides " + << "already set \"deny\" tag. " + << "Either \"deny\" or \"allow\" is allowed."; + } + allow_deny_set = true; + policy->allow_what_ = true; + load_policy_body(policy, i); + } else if (i->first == "deny") { + if (allow_deny_set) { + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: \"deny\" tag overrides " + << "already set \"allow\" tag. " + << "Either \"deny\" or \"allow\" is allowed."; + } + allow_deny_set = true; + policy->allow_what_ = false; + load_policy_body(policy, i); + } + } + boost::unique_lock<boost::shared_mutex> its_lock(any_client_policies_mutex_); + if (!exist_in_any_client_policies_unlocked(policy)) + any_client_policies_.push_back(policy); + +} + +void +policy_manager_impl::load_policy_body(std::shared_ptr<policy> &_policy, + const boost::property_tree::ptree::const_iterator &_tree) { + + for (auto l = _tree->second.begin(); l != _tree->second.end(); ++l) { + if (l->first == "requests") { + for (auto n = l->second.begin(); n != l->second.end(); ++n) { + service_t its_service = 0x0; + instance_t its_instance = 0x0; + boost::icl::interval_map<instance_t, + boost::icl::interval_set<method_t> > its_instance_method_intervals; + for (auto k = n->second.begin(); k != n->second.end(); ++k) { + if (k->first == "service") { + read_data(k->second.data(), its_service); + } else if (k->first == "instance") { // legacy definition for instances + boost::icl::interval_set<instance_t> its_instance_interval_set; + boost::icl::interval_set<method_t> its_method_interval_set; + boost::icl::discrete_interval<instance_t> all_instances(0x01, 0xFFFF, + boost::icl::interval_bounds::closed()); + boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF, + boost::icl::interval_bounds::closed()); + + std::string its_value(k->second.data()); + if (its_value != "any") { + read_data(its_value, its_instance); + if (its_instance != 0x0) { + its_instance_interval_set.insert(its_instance); + its_method_interval_set.insert(all_methods); + } + } else { + its_instance_interval_set.insert(all_instances); + its_method_interval_set.insert(all_methods); + } + for (const auto i : its_instance_interval_set) { + its_instance_method_intervals + += std::make_pair(i, its_method_interval_set); + } + } else if (k->first == "instances") { // new instances definition + for (auto p = k->second.begin(); p != k->second.end(); ++p) { + boost::icl::interval_set<instance_t> its_instance_interval_set; + boost::icl::interval_set<method_t> its_method_interval_set; + boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF, + boost::icl::interval_bounds::closed()); + for (auto m = p->second.begin(); m != p->second.end(); ++m) { + if (m->first == "ids") { + load_interval_set(m->second, its_instance_interval_set); + } else if (m->first == "methods") { + load_interval_set(m->second, its_method_interval_set); + } + } + if (its_method_interval_set.empty()) + its_method_interval_set.insert(all_methods); + for (const auto i : its_instance_interval_set) { + its_instance_method_intervals + += std::make_pair(i, its_method_interval_set); + } + } + + if (its_instance_method_intervals.empty()) { + boost::icl::interval_set<instance_t> its_legacy_instance_interval_set; + boost::icl::interval_set<method_t> its_legacy_method_interval_set; + boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF, + boost::icl::interval_bounds::closed()); + its_legacy_method_interval_set.insert(all_methods); + + // try to only load instance ranges with any method to be allowed + load_interval_set(k->second, its_legacy_instance_interval_set); + for (const auto i : its_legacy_instance_interval_set) { + its_instance_method_intervals + += std::make_pair(i, its_legacy_method_interval_set); + } + } + } + } + if (its_service != 0x0 && !its_instance_method_intervals.empty()) { + _policy->requests_ += std::make_pair( + boost::icl::discrete_interval<service_t>( + its_service, its_service, + boost::icl::interval_bounds::closed()), + its_instance_method_intervals); + } + } + } else if (l->first == "offers") { + for (auto n = l->second.begin(); n != l->second.end(); ++n) { + service_t its_service(0x0); + instance_t its_instance(0x0); + boost::icl::interval_set<instance_t> its_instance_interval_set; + for (auto k = n->second.begin(); k != n->second.end(); ++k) { + if (k->first == "service") { + read_data(k->second.data(), its_service); + } else if (k->first == "instance") { // legacy definition for instances + std::string its_value(k->second.data()); + if (its_value != "any") { + read_data(its_value, its_instance); + if (its_instance != 0x0) { + its_instance_interval_set.insert(its_instance); + } + } else { + its_instance_interval_set.insert( + boost::icl::discrete_interval<instance_t>( + 0x0001, 0xFFFF)); + } + } else if (k->first == "instances") { // new instances definition + load_interval_set(k->second, its_instance_interval_set); + } + } + if (its_service != 0x0 && !its_instance_interval_set.empty()) { + _policy->offers_ + += std::make_pair( + boost::icl::discrete_interval<service_t>( + its_service, its_service, + boost::icl::interval_bounds::closed()), + its_instance_interval_set); + } + } + } + } +} + + +void +policy_manager_impl::load_credential( + const boost::property_tree::ptree &_tree, + boost::icl::interval_map<uid_t, + boost::icl::interval_set<gid_t> > &_credentials) { + + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + boost::icl::interval_set<uid_t> its_uid_interval_set; + boost::icl::interval_set<gid_t> its_gid_interval_set; + + for (auto j = i->second.begin(); j != i->second.end(); ++j) { + std::string its_key(j->first); + if (its_key == "uid") { + load_interval_set(j->second, its_uid_interval_set); + } else if (its_key == "gid") { + load_interval_set(j->second, its_gid_interval_set); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: " + << "Malformed credential (contains illegal key \"" + << its_key << "\")"; + } + } + + for (const auto its_uid_interval : its_uid_interval_set) { + _credentials + += std::make_pair(its_uid_interval, its_gid_interval_set); + } + } +} + +bool +policy_manager_impl::load_routing_credentials(const configuration_element &_element) { + try { + auto its_routing_cred = _element.tree_.get_child("routing-credentials"); + if (is_configured_) { + VSOMEIP_WARNING << "vSomeIP Security: Multiple definitions of routing-credentials." + << " Ignoring definition from " << _element.name_; + } else { + for (auto i = its_routing_cred.begin(); + i != its_routing_cred.end(); + ++i) { + std::string its_key(i->first); + std::string its_value(i->second.data()); + if (its_key == "uid") { + uint32_t its_uid(0); + read_data(its_value, its_uid); + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + std::get<0>(routing_credentials_) = its_uid; + } else if (its_key == "gid") { + uint32_t its_gid(0); + read_data(its_value, its_gid); + std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_); + std::get<1>(routing_credentials_) = its_gid; + } + } + check_routing_credentials_ = true; + is_configured_ = true; + } + } catch (...) { + return false; + } + return true; +} + + +void +policy_manager_impl::load_security_update_whitelist(const configuration_element &_element) { +#ifdef _WIN32 + return; +#endif + try { + auto optional = _element.tree_.get_child_optional("security-update-whitelist"); + if (!optional) { + return; + } + auto found_whitelist = _element.tree_.get_child("security-update-whitelist"); + for (auto its_whitelist = found_whitelist.begin(); + its_whitelist != found_whitelist.end(); ++its_whitelist) { + + if (its_whitelist->first == "uids") { + { + std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_); + load_interval_set(its_whitelist->second, uid_whitelist_); + } + } else if (its_whitelist->first == "services") { + { + std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_); + load_interval_set(its_whitelist->second, service_interface_whitelist_); + } + } else if (its_whitelist->first == "check-whitelist") { + if (its_whitelist->second.data() == "true") { + check_whitelist_ = true; + } else { + check_whitelist_ = false; + } + } + } + } catch (...) { + } +} + +void +policy_manager_impl::load_security_policy_extensions(const configuration_element &_element) { +#ifdef _WIN32 + return; +#endif + try { + auto optional = _element.tree_.get_child_optional("container_policy_extensions"); + if (!optional) { + return; + } + auto found_policy_extensions = _element.tree_.get_child("container_policy_extensions"); + boost::filesystem::path its_base_path; + { + boost::unique_lock<boost::shared_mutex> its_lock(policy_extension_paths_mutex_); + its_base_path = boost::filesystem::path(policy_base_path_); + } + + for (auto i = found_policy_extensions.begin(); + i != found_policy_extensions.end(); ++i) { + boost::filesystem::path its_canonical_path; + std::string its_client_host(""); + std::string its_path(""); + auto its_data = i->second; + for (auto j = its_data.begin(); j != its_data.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "container") { + if(its_value != "") { + its_client_host = its_value; + } + } else if (its_key == "path") { + if(its_value != "") { + its_path = its_value; + } + } + } + + std::string str = VSOMEIP_DEFAULT_CONFIGURATION_FOLDER; + std::string its_filesystem_path = str.substr(0, str.find_last_of("\\/")) + + its_path.erase(0, its_path.find_first_of("\\/")); + + if (!utility::is_folder(its_filesystem_path)) { + VSOMEIP_DEBUG << __func__ << ": The path " + << its_filesystem_path + << " is not valid"; + } + std::map<std::string, bool> empty_map; + policy_extension_paths_[its_client_host] = std::make_pair(its_filesystem_path, empty_map); + + VSOMEIP_INFO << __func__ << ": Insert policy extension path: [" << its_filesystem_path + << "] for hostname: [" << its_client_host << "]"; + } + } catch (...) { + } +} + +template<typename T_> +void policy_manager_impl::load_interval_set( + const boost::property_tree::ptree &_tree, + boost::icl::interval_set<T_> &_intervals, bool _exclude_margins) { + + boost::icl::interval_set<T_> its_intervals; + T_ its_min = std::numeric_limits<T_>::min(); + T_ its_max = std::numeric_limits<T_>::max(); + + if (_exclude_margins) { + its_min++; + its_max--; + } + + const std::string its_key(_tree.data()); + if (its_key == "any") { + its_intervals.insert(boost::icl::discrete_interval<T_>::closed( + its_min, its_max)); + } else { + for (auto i = _tree.begin(); i != _tree.end(); ++i) { + auto its_data = i->second; + if (!its_data.data().empty()) { + T_ its_id; + read_data(its_data.data(), its_id); + if (its_id >= its_min && its_id <= its_max) + its_intervals.insert(its_id); + } else { + T_ its_first, its_last; + bool has_first(false), has_last(false); + for (auto j = its_data.begin(); j != its_data.end(); ++j) { + std::string its_key(j->first); + std::string its_value(j->second.data()); + if (its_key == "first") { + if (its_value == "min") { + its_first = its_min; + } else { + read_data(its_value, its_first); + } + has_first = true; + } else if (its_key == "last") { + if (its_value == "max") { + its_last = its_max; + } else { + read_data(its_value, its_last); + } + has_last = true; + } else { + VSOMEIP_WARNING << "vSomeIP Security: Security configuration: " + << " Malformed range. Contains illegal key (" + << its_key << ")"; + } + } + if (has_first && has_last && its_first <= its_last) { + its_intervals.insert( + boost::icl::discrete_interval<T_>::closed(its_first, its_last)); + } + } + } + } + + _intervals = its_intervals; +} + +void +policy_manager_impl::get_requester_policies(const std::shared_ptr<policy> _policy, + std::set<std::shared_ptr<policy> > &_requesters) const { + + std::scoped_lock its_lock {any_client_policies_mutex_, _policy->mutex_}; + for (const auto &o : _policy->offers_) { + for (const auto &p : any_client_policies_) { + if (p == _policy) + continue; + + std::lock_guard<std::mutex> its_lock(p->mutex_); + + auto its_policy = std::make_shared<policy>(); + its_policy->credentials_ = p->credentials_; + + for (const auto &r : p->requests_) { + // o represents an offer by a service interval and its instances + // (a set of intervals) + // r represents a request by a service interval and its instances + // and methods (instance intervals mapped to interval sets of methods) + // + // Thus, r matches o if their service identifiers as well as their + // instances overlap. If r and o match, a new policy must be + // created that contains the overlapping services/instances mapping + // of r and o together with the methods from r + service_t its_o_lower, its_o_upper, its_r_lower, its_r_upper; + get_bounds(o.first, its_o_lower, its_o_upper); + get_bounds(r.first, its_r_lower, its_r_upper); + + if (its_o_lower <= its_r_upper && its_r_lower <= its_o_upper) { + auto its_service_min = std::max(its_o_lower, its_r_lower); + auto its_service_max = std::min(its_r_upper, its_o_upper); + + for (const auto &i : o.second) { + for (const auto &j : r.second) { + for (const auto &k : j.second) { + instance_t its_i_lower, its_i_upper, its_k_lower, its_k_upper; + get_bounds(i, its_i_lower, its_i_upper); + get_bounds(k, its_k_lower, its_k_upper); + + if (its_i_lower <= its_k_upper && its_k_lower <= its_i_upper) { + auto its_instance_min = std::max(its_i_lower, its_k_lower); + auto its_instance_max = std::min(its_i_upper, its_k_upper); + + boost::icl::interval_map<instance_t, + boost::icl::interval_set<method_t> > its_instances_methods; + its_instances_methods += std::make_pair( + boost::icl::interval<instance_t>::closed( + its_instance_min, its_instance_max), + j.second); + + its_policy->requests_ += std::make_pair( + boost::icl::interval<instance_t>::closed( + its_service_min, its_service_max), + its_instances_methods); + } + } + } + } + } + } + + if (!its_policy->requests_.empty()) { + _requesters.insert(its_policy); + } + } + } +} + +void +policy_manager_impl::get_clients(uid_t _uid, gid_t _gid, + std::unordered_set<client_t> &_clients) const { + + std::lock_guard<std::mutex> its_lock(ids_mutex_); + for (const auto &i : ids_) { + if (i.second.port == VSOMEIP_SEC_PORT_UNUSED + && i.second.user == _uid + && i.second.group == _gid) + _clients.insert(i.first); + } +} + +bool +policy_manager_impl::is_policy_extension(const std::string &_path) const { + auto its_pos = _path.find("vsomeip_policy_extensions.json"); + if (its_pos != std::string::npos) { + return true; + } + return false; +} + +void +policy_manager_impl::set_policy_extension_base_path(const std::string &_path) { + auto its_pos = _path.find("vsomeip_policy_extensions.json"); + std::lock_guard<std::mutex> its_lock(policy_base_path_mutex_); + policy_base_path_ = _path.substr(0, its_pos); +} + +std::string +policy_manager_impl::get_policy_extension_path(const std::string &_client_host) const { + boost::shared_lock<boost::shared_mutex> lock(policy_extension_paths_mutex_); + return get_policy_extension_path_unlocked(_client_host); +} +//only be called after loading of the mutex +std::string +policy_manager_impl::get_policy_extension_path_unlocked(const std::string &_client_host) const { + std::string its_path(""); + + auto found_host = policy_extension_paths_.find(_client_host); + + if (found_host != policy_extension_paths_.end()) { + its_path = found_host->second.first; + } + return its_path; +} + +policy_manager_impl::policy_loaded_e +policy_manager_impl::is_policy_extension_loaded(const std::string &_client_host) const { + boost::shared_lock<boost::shared_mutex> lock(policy_extension_paths_mutex_); + + auto found_host = policy_extension_paths_.find(_client_host); + if (found_host != policy_extension_paths_.end()) { + + auto found_complete_path = found_host->second.second.find( + get_security_config_folder(found_host->second.first)); + if (found_complete_path != found_host->second.second.end()) { + if (found_complete_path->second) { + return policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_LOADED; + } else { + return policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_NOT_LOADED; + } + } + } + + // we do not have a path to load + return policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT; +} + +void +policy_manager_impl::set_is_policy_extension_loaded(const std::string &_client_host, + const bool _loaded) { + boost::unique_lock<boost::shared_mutex> lock(policy_extension_paths_mutex_); + auto found_host = policy_extension_paths_.find(_client_host); + + if (found_host != policy_extension_paths_.end()) { + std::string its_folder = get_policy_extension_path_unlocked(_client_host); + std::string its_complete_folder = get_security_config_folder(its_folder); + + // if the map key of complete path folder exist, will be updated + // if not will create an new entry + found_host->second.second[its_complete_folder] = _loaded; + } +} + +std::string +policy_manager_impl::get_security_config_folder(const std::string &its_folder) const +{ + std::stringstream its_security_config_folder; + its_security_config_folder << its_folder; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + its_security_config_folder << "/" << getuid() << "_" << getgid(); +#endif + + if (utility::is_folder(its_security_config_folder.str())) { + return its_security_config_folder.str(); + } else { + VSOMEIP_INFO << __func__<< ": Invalid folder for " << its_security_config_folder.str(); + } + return std::string(""); +} + +std::shared_ptr<policy> +policy_manager_impl::create_policy() const { + return std::make_shared<policy>(); +} + +void +policy_manager_impl::print_policy(const std::shared_ptr<policy> &_policy) const { + + if (_policy) + _policy->print(); +} + +bool +policy_manager_impl::parse_uid_gid(const byte_t* &_buffer, + uint32_t &_buffer_size, uid_t &_uid, gid_t &_gid) const { + + const auto its_policy = std::make_shared<policy>(); + return (its_policy + && its_policy->deserialize_uid_gid(_buffer, _buffer_size, _uid, _gid)); +} + +#endif // !VSOMEIP_DISABLE_SECURITY + +bool +policy_manager_impl::store_client_to_sec_client_mapping( + client_t _client, const vsomeip_sec_client_t *_sec_client) { + + if (_sec_client != nullptr && _sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + // store the client -> sec_client mapping + std::lock_guard<std::mutex> its_lock(ids_mutex_); + auto found_client = ids_.find(_client); + if (found_client != ids_.end()) { + if (!utility::compare(found_client->second, *_sec_client)) { + uid_t its_old_uid = found_client->second.user; + gid_t its_old_gid = found_client->second.group; + uid_t its_new_uid = _sec_client->user; + gid_t its_new_gid = _sec_client->group; + + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" + << std::hex << _client << " with UID/GID=" + << std::dec << its_new_uid << "/" << its_new_gid + << " : Overwriting existing credentials UID/GID=" + << std::dec << its_old_uid << "/" << its_old_gid; + + found_client->second = *_sec_client; + return true; + } + } else { + ids_[_client] = *_sec_client; + } + return true; + } + + return false; +} + +bool +policy_manager_impl::get_client_to_sec_client_mapping(client_t _client, + vsomeip_sec_client_t &_sec_client) { + { + // get the UID / GID of the client + std::lock_guard<std::mutex> its_lock(ids_mutex_); + if (ids_.find(_client) != ids_.end()) { + _sec_client = ids_[_client]; + return true; + } + return false; + } +} + +bool +policy_manager_impl::remove_client_to_sec_client_mapping(client_t _client) { + + vsomeip_sec_client_t its_sec_client; + bool is_client_removed(false); + bool is_sec_client_removed(false); + { + std::lock_guard<std::mutex> its_lock(ids_mutex_); + auto found_client = ids_.find(_client); + if (found_client != ids_.end()) { + its_sec_client = found_client->second; + ids_.erase(found_client); + is_client_removed = true; + } + } + { + std::lock_guard<std::mutex> its_lock(sec_client_to_clients_mutex_); + if (is_client_removed) { + auto found_sec_client = sec_client_to_clients_.find(its_sec_client); + if (found_sec_client != sec_client_to_clients_.end()) { + auto its_client = found_sec_client->second.find(_client); + if (its_client != found_sec_client->second.end()) { + found_sec_client->second.erase(its_client); + if (found_sec_client->second.empty()) { + sec_client_to_clients_.erase(found_sec_client); + } + is_sec_client_removed = true; + } + } + } else { + for (auto it = sec_client_to_clients_.begin(); + it != sec_client_to_clients_.end(); ++it) { + auto its_client = it->second.find(_client); + if (its_client != it->second.end()) { + it->second.erase(its_client); + if (it->second.empty()) { + sec_client_to_clients_.erase(it); + } + is_sec_client_removed = true; + break; + } + } + } + } + + return (is_client_removed && is_sec_client_removed); +} + +void +policy_manager_impl::store_sec_client_to_client_mapping( + const vsomeip_sec_client_t *_sec_client, client_t _client) { + + if (_sec_client && _sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + // store the uid gid to clients mapping + std::lock_guard<std::mutex> its_lock(sec_client_to_clients_mutex_); + auto found_sec_client = sec_client_to_clients_.find(*_sec_client); + if (found_sec_client != sec_client_to_clients_.end()) { + found_sec_client->second.insert(_client); + } else { + std::set<client_t> mapped_clients; + mapped_clients.insert(_client); + sec_client_to_clients_.insert(std::make_pair(*_sec_client, mapped_clients)); + } + } +} + +bool +policy_manager_impl::get_sec_client_to_clients_mapping( + const vsomeip_sec_client_t *_sec_client, + std::set<client_t> &_clients) { + + if (_sec_client && _sec_client->port == VSOMEIP_SEC_PORT_UNUSED) { + // get the clients corresponding to uid, gid + std::lock_guard<std::mutex> its_lock(sec_client_to_clients_mutex_); + auto found_sec_client = sec_client_to_clients_.find(*_sec_client); + if (found_sec_client != sec_client_to_clients_.end()) { + _clients = found_sec_client->second; + return true; + } + } + return false; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/security.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/security.cpp new file mode 100644 index 00000000000..e17e3473001 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/security/src/security.cpp @@ -0,0 +1,194 @@ +// Copyright (C) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/security.hpp" +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/internal/plugin_manager.hpp> +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif +#include "../../configuration/include/configuration_plugin.hpp" +#include "../../configuration/include/configuration_impl.hpp" + +#include <array> +#include <iomanip> +#include <tuple> + +#ifndef _WIN32 +#include <dlfcn.h> +#endif + +template<class T_> +std::function<T_> security_load_function(void *_library, std::string const &_name) { + void *its_function; +#ifdef _WIN32 + its_function = GetProcAddress(reinterpret_cast<HMODULE>(_library), _name.c_str()); +#else + its_function = dlsym(_library, _name.c_str()); +#endif + if (!its_function) { + VSOMEIP_ERROR << __func__ + << ": security library misses \"" + << _name + << "\" function."; + return nullptr; + } + + return reinterpret_cast<T_*>(its_function); +} + +#define VSOMEIP_SECURITY_LOAD_IMPL(symbol, variable) \ + auto variable = security_load_function<decltype(symbol)>(its_library, #symbol); \ + if (!variable) { \ + its_manager->unload_library(its_library); \ + return false; \ + } + +#define VSOMEIP_SECURITY_LOAD(name) \ + VSOMEIP_SECURITY_LOAD_IMPL(vsomeip_sec_##name, loaded_##name) + +#define VSOMEIP_SECURITY_POLICY_LOAD(name) \ + VSOMEIP_SECURITY_LOAD_IMPL(vsomeip_sec_policy_##name, loaded_##name) + +#define VSOMEIP_SECURITY_ASSIGN_FUNCTION(name) \ + name = loaded_##name + +namespace vsomeip_v3 { + +security::security(std::shared_ptr<policy_manager_impl> _policy_manager): + policy_manager_(_policy_manager) { + + initialize = [&]() -> vsomeip_sec_policy_result_t { + return default_initialize(); + }; + + authenticate_router = [&](const vsomeip_sec_client_t *_server) -> vsomeip_sec_acl_result_t { + return default_authenticate_router(_server); + }; + + is_client_allowed_to_offer = [&](const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance) -> vsomeip_sec_acl_result_t { + return default_is_client_allowed_to_offer(_client, _service, _instance); + }; + + is_client_allowed_to_request = [&](const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance) -> vsomeip_sec_acl_result_t { + return default_is_client_allowed_to_request(_client, _service, _instance); + }; + + is_client_allowed_to_access_member = [&](const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance, + vsomeip_sec_member_id_t _member) -> vsomeip_sec_acl_result_t { + return default_is_client_allowed_to_access_member(_client, _service, + _instance, _member); + }; + + sync_client = [&](vsomeip_sec_client_t *_client) { + return default_sync_client(_client); + }; +} + +bool +security::load() { + if (auto its_manager = plugin_manager::get()) { + if (auto its_library = its_manager->load_library(VSOMEIP_SEC_LIBRARY)) { + + VSOMEIP_SECURITY_POLICY_LOAD(initialize); + VSOMEIP_SECURITY_POLICY_LOAD(authenticate_router); + VSOMEIP_SECURITY_POLICY_LOAD(is_client_allowed_to_offer); + VSOMEIP_SECURITY_POLICY_LOAD(is_client_allowed_to_request); + VSOMEIP_SECURITY_POLICY_LOAD(is_client_allowed_to_access_member); + VSOMEIP_SECURITY_LOAD(sync_client); + + // All symbols could be loaded, assign them + VSOMEIP_SECURITY_ASSIGN_FUNCTION(initialize); + VSOMEIP_SECURITY_ASSIGN_FUNCTION(authenticate_router); + VSOMEIP_SECURITY_ASSIGN_FUNCTION(is_client_allowed_to_offer); + VSOMEIP_SECURITY_ASSIGN_FUNCTION(is_client_allowed_to_request); + VSOMEIP_SECURITY_ASSIGN_FUNCTION(is_client_allowed_to_access_member); + VSOMEIP_SECURITY_ASSIGN_FUNCTION(sync_client); + + // Symbol loading complete, success! + return true; + } else { +#ifdef _WIN32 + VSOMEIP_ERROR << "vSomeIP Security: Loading " << VSOMEIP_SEC_LIBRARY << " failed."; +#else + VSOMEIP_ERROR << "vSomeIP Security: " << dlerror(); +#endif + } + } + + return false; +} + +// +// Default interface implementation +// +vsomeip_sec_policy_result_t +security::default_initialize() { + return VSOMEIP_SEC_POLICY_OK; +} + +vsomeip_sec_acl_result_t +security::default_authenticate_router(const vsomeip_sec_client_t *_server) { + + if (_server && _server->port != VSOMEIP_SEC_PORT_UNUSED) + return VSOMEIP_SEC_OK; + + if (policy_manager_->check_routing_credentials(_server)) + return VSOMEIP_SEC_OK; + else + return VSOMEIP_SEC_PERM_DENIED; +} + +vsomeip_sec_acl_result_t +security::default_is_client_allowed_to_offer(const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance) { + + if (_client && _client->port != VSOMEIP_SEC_PORT_UNUSED) + return VSOMEIP_SEC_OK; + + if (policy_manager_->is_offer_allowed(_client, _service, _instance)) + return VSOMEIP_SEC_OK; + else + return VSOMEIP_SEC_PERM_DENIED; +} + +vsomeip_sec_acl_result_t +security::default_is_client_allowed_to_request(const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance) { + + if (_client && _client->port != VSOMEIP_SEC_PORT_UNUSED) + return VSOMEIP_SEC_OK; + + if (policy_manager_->is_client_allowed(_client, _service, _instance, 0x00, true)) + return VSOMEIP_SEC_OK; + else + return VSOMEIP_SEC_PERM_DENIED; +} + +vsomeip_sec_acl_result_t +security::default_is_client_allowed_to_access_member(const vsomeip_sec_client_t *_client, + vsomeip_sec_service_id_t _service, vsomeip_sec_instance_id_t _instance, + vsomeip_sec_member_id_t _member) { + + if (_client && _client->port != VSOMEIP_SEC_PORT_UNUSED) + return VSOMEIP_SEC_OK; + + if (policy_manager_->is_client_allowed(_client, _service, _instance, _member, false)) + return VSOMEIP_SEC_OK; + else + return VSOMEIP_SEC_PERM_DENIED; +} + +void +security::default_sync_client(vsomeip_sec_client_t *_client) { + (void)_client; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/configuration_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/configuration_option_impl.hpp new file mode 100644 index 00000000000..e1dde72cf0f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/configuration_option_impl.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_CONFIGURATION_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_CONFIGURATION_OPTION_IMPL_HPP_ + +#include <map> +#include <string> +#include <vector> + +#include "option_impl.hpp" + +namespace vsomeip_v3 { + +class serializer; +class deserializer; + +namespace sd { + +class configuration_option_impl: public option_impl { + +public: + configuration_option_impl(); + virtual ~configuration_option_impl(); + + bool equals(const option_impl &_other) const; + + void add_item(const std::string &_key, const std::string &_value); + void remove_item(const std::string &_key); + + std::vector<std::string> get_keys() const; + std::vector<std::string> get_values() const; + std::string get_value(const std::string &_key) const; + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + std::map<std::string, std::string> configuration_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_CONFIGURATION_OPTION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/constants.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/constants.hpp new file mode 100644 index 00000000000..3ebb259fe27 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/constants.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_CONSTANTS_HPP_ +#define VSOMEIP_V3_SD_CONSTANTS_HPP_ + +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +namespace sd { + +const service_t service = 0xFFFF; +const instance_t instance = 0x0000; +const method_t method = 0x8100; +const client_t client = 0x0000; +const protocol_version_t protocol_version = 0x01; +const interface_version_t interface_version = 0x01; +const message_type_e message_type = message_type_e::MT_NOTIFICATION; +const return_code_e return_code = return_code_e::E_OK; + +namespace protocol { + +const uint8_t reserved_byte = 0x0; +const uint16_t reserved_word = 0x0; +const uint32_t reserved_long = 0x0; + +const uint8_t tcp = 0x06; +const uint8_t udp = 0x11; + +} // namespace protocol +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_CONSTANTS_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/defines.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/defines.hpp new file mode 100644 index 00000000000..b7642f12277 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/defines.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_SD_DEFINES_HPP +#define VSOMEIP_SD_DEFINES_HPP + +#define VSOMEIP_MAX_TCP_SD_PAYLOAD 4075 // Available for entries & options +#define VSOMEIP_MAX_UDP_SD_PAYLOAD 1380 + +#define VSOMEIP_SOMEIP_SD_DATA_SIZE 12 +#define VSOMEIP_SOMEIP_SD_ENTRY_LENGTH_SIZE 4 +#define VSOMEIP_SOMEIP_SD_ENTRY_SIZE 16 +#define VSOMEIP_SOMEIP_SD_IPV3_OPTION_SIZE 12 +#define VSOMEIP_SOMEIP_SD_IPV6_OPTION_SIZE 24 +#define VSOMEIP_SOMEIP_SD_LOAD_BALANCING_OPTION_SIZE 8 +#define VSOMEIP_SOMEIP_SD_PROTECTION_OPTION_SIZE 12 + +#define VSOMEIP_SOMEIP_SD_OPTION_LENGTH_SIZE 4 +#define VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE 3 +#define VSOMEIP_SOMEIP_SD_EMPTY_MESSAGE_SIZE 28 +#define VSOMEIP_SOMEIP_SD_SPACE_FOR_PAYLOAD VSOMEIP_MAX_UDP_MESSAGE_SIZE - VSOMEIP_SOMEIP_SD_EMPTY_MESSAGE_SIZE; + + + +#define VSOMEIP_SD_IPV4_OPTION_LENGTH 0x0009 +#define VSOMEIP_SD_IPV6_OPTION_LENGTH 0x0015 + +#define VSOMEIP_SD_SERVICE 0xFFFF +#define VSOMEIP_SD_INSTANCE 0x0000 +#define VSOMEIP_SD_METHOD 0x8100 +#define VSOMEIP_SD_CLIENT 0x0 + + +#define VSOMEIP_SD_DEFAULT_ENABLED true +#define VSOMEIP_SD_DEFAULT_PROTOCOL "udp" +#define VSOMEIP_SD_DEFAULT_MULTICAST "224.224.224.0" +#define VSOMEIP_SD_DEFAULT_PORT 30490 + +#define VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MIN 0 +#define VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX 3000 +#define VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY 10 +#define VSOMEIP_SD_DEFAULT_REPETITIONS_MAX 3 +#define VSOMEIP_SD_DEFAULT_TTL DEFAULT_TTL +#define VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY 1000 +#define VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY 2000 +#define VSOMEIP_SD_DEFAULT_OFFER_DEBOUNCE_TIME 500 +#define VSOMEIP_SD_DEFAULT_FIND_DEBOUNCE_TIME 500 + + +#endif // VSOMEIP_SD_DEFINES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/deserializer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/deserializer.hpp new file mode 100644 index 00000000000..866ebda3a15 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/deserializer.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_DESERIALIZER_HPP +#define VSOMEIP_V3_SD_DESERIALIZER_HPP + +#include "../../message/include/deserializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class message_impl; + +class deserializer + : public vsomeip_v3::deserializer { +public: + deserializer(std::uint32_t _shrink_buffer_threshold); + deserializer(uint8_t *_data, std::size_t _length, + std::uint32_t _shrink_buffer_threshold); + deserializer(const deserializer &_other); + virtual ~deserializer(); + + message_impl * deserialize_sd_message(); +}; + +} // namespace sd +} // vsomeip_v3 + +#endif // VSOMEIP_V3_SD_DESERIALIZER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/entry_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/entry_impl.hpp new file mode 100644 index 00000000000..ed22c8ffc7f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/entry_impl.hpp @@ -0,0 +1,81 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_ENTRY_IMPL_HPP +#define VSOMEIP_V3_SD_ENTRY_IMPL_HPP + +#include <memory> +#include <vector> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/internal/serializable.hpp> + +#include "enumeration_types.hpp" +#include "message_element_impl.hpp" + +#define VSOMEIP_MAX_OPTION_RUN 2 + +namespace vsomeip_v3 { + +class deserializer; + +namespace sd { + +class option_impl; +class message_impl; + +class entry_impl: public message_element_impl { +public: + virtual ~entry_impl(); + + // public interface + entry_type_e get_type() const; + + service_t get_service() const; + void set_service(service_t _service); + + instance_t get_instance() const; + void set_instance(instance_t _instance); + + major_version_t get_major_version() const; + void set_major_version(major_version_t _major_version); + + ttl_t get_ttl() const; + void set_ttl(ttl_t _ttl); + + const std::vector<uint8_t> & get_options(uint8_t _run) const; + void assign_option(const std::shared_ptr<option_impl> &_option); + + bool is_service_entry() const; + bool is_eventgroup_entry() const; + + void set_type(entry_type_e _type); + + virtual bool serialize(vsomeip_v3::serializer *_to) const; + virtual bool deserialize(vsomeip_v3::deserializer *_from); + + uint8_t get_num_options(uint8_t _run) const; + +protected: + entry_type_e type_; + service_t service_; + instance_t instance_; + major_version_t major_version_; + ttl_t ttl_; + + std::vector<uint8_t> options_[VSOMEIP_MAX_OPTION_RUN]; + + uint8_t num_options_[VSOMEIP_MAX_OPTION_RUN]; + std::uint8_t index1_; + std::uint8_t index2_; + + entry_impl(); + entry_impl(const entry_impl &_entry); +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_ENTRY_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/enumeration_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/enumeration_types.hpp new file mode 100644 index 00000000000..0b6c71b8aea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/enumeration_types.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstdint> + +#ifndef VSOMEIP_V3_SD_ENUMERATION_TYPES_HPP +#define VSOMEIP_V3_SD_ENUMERATION_TYPES_HPP + +namespace vsomeip_v3 { +namespace sd { + +enum class option_type_e + : uint8_t { + CONFIGURATION = 0x1, + LOAD_BALANCING = 0x2, + PROTECTION = 0x3, + IP4_ENDPOINT = 0x4, + IP6_ENDPOINT = 0x6, + IP4_MULTICAST = 0x14, + IP6_MULTICAST = 0x16, + SELECTIVE = 0x20, + UNKNOWN = 0xFF +}; + +enum class entry_type_e + : uint8_t { + FIND_SERVICE = 0x00, + OFFER_SERVICE = 0x01, + STOP_OFFER_SERVICE = 0x01, + REQUEST_SERVICE = 0x2, + FIND_EVENT_GROUP = 0x4, + PUBLISH_EVENTGROUP = 0x5, + STOP_PUBLISH_EVENTGROUP = 0x5, + SUBSCRIBE_EVENTGROUP = 0x06, + STOP_SUBSCRIBE_EVENTGROUP = 0x06, + SUBSCRIBE_EVENTGROUP_ACK = 0x07, + STOP_SUBSCRIBE_EVENTGROUP_ACK = 0x07, + UNKNOWN = 0xFF +}; + +enum class layer_four_protocol_e + : uint8_t { + TCP = 0x06, + UDP = 0x11, + UNKNOWN = 0xFF +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_ENUMERATION_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/eventgroupentry_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/eventgroupentry_impl.hpp new file mode 100644 index 00000000000..efb9b07c3f6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/eventgroupentry_impl.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_EVENTGROUPENTRY_IMPL_HPP_ +#define VSOMEIP_V3_SD_EVENTGROUPENTRY_IMPL_HPP_ + +#include "entry_impl.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" +#include "message_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class selective_option_impl; + +class eventgroupentry_impl: public entry_impl { +public: + eventgroupentry_impl(); + eventgroupentry_impl(const eventgroupentry_impl &_entry); + virtual ~eventgroupentry_impl(); + + eventgroup_t get_eventgroup() const; + void set_eventgroup(eventgroup_t _eventgroup); + + uint16_t get_reserved() const; + void set_reserved(uint16_t _reserved); + + uint8_t get_counter() const; + void set_counter(uint8_t _counter); + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + + bool operator==(const eventgroupentry_impl& _other) const { + return (ttl_ == _other.ttl_ && + service_ == _other.service_ && + instance_ == _other.instance_ && + eventgroup_ == _other.eventgroup_ && + index1_ == _other.index1_ && + index2_ == _other.index2_ && + num_options_[0] == _other.num_options_[0] && + num_options_[1] == _other.num_options_[1] && + major_version_ == _other.major_version_ && + counter_ == _other.counter_); + } + + bool matches(const eventgroupentry_impl &_other, + const message_impl::options_t &_options) const; + + void add_target(const std::shared_ptr<endpoint_definition> &_target); + std::shared_ptr<endpoint_definition> get_target(bool _reliable) const; + + std::shared_ptr<selective_option_impl> get_selective_option() const; + +private: + eventgroup_t eventgroup_; + uint16_t reserved_; + + // counter field to differentiate parallel subscriptions on same event group + // 4Bit only (max 16. parralel subscriptions) + uint8_t counter_; + + std::shared_ptr<endpoint_definition> target_reliable_; + std::shared_ptr<endpoint_definition> target_unreliable_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_EVENTGROUPENTRY_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ip_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ip_option_impl.hpp new file mode 100644 index 00000000000..842be840871 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ip_option_impl.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_IP_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_IP_OPTION_IMPL_HPP_ + +#include <vsomeip/primitive_types.hpp> + +#include "option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class ip_option_impl + : public option_impl { +public: + ip_option_impl(); + ip_option_impl(const uint16_t _port, const bool _is_reliable); + virtual ~ip_option_impl(); + bool equals(const option_impl &_other) const; + + uint16_t get_port() const; + void set_port(uint16_t _port); + + layer_four_protocol_e get_layer_four_protocol() const; + void set_layer_four_protocol(layer_four_protocol_e _protocol); + + virtual bool is_multicast() const = 0; + + virtual bool serialize(vsomeip_v3::serializer *_to) const = 0; + virtual bool deserialize(vsomeip_v3::deserializer *_from) = 0; + +protected: + layer_four_protocol_e protocol_; + uint16_t port_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_IP_OPTION_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv4_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv4_option_impl.hpp new file mode 100644 index 00000000000..7e9707849a1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv4_option_impl.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_IPV3_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_IPV3_OPTION_IMPL_HPP_ + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> + +#include "ip_option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class ipv4_option_impl: public ip_option_impl { +public: + ipv4_option_impl(); + ipv4_option_impl(const boost::asio::ip::address &_address, + const uint16_t _port, const bool _is_reliable); + virtual ~ipv4_option_impl(); + + bool equals(const option_impl &_other) const; + + const ipv4_address_t & get_address() const; + void set_address(const ipv4_address_t &_address); + + bool is_multicast() const; + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + ipv4_address_t address_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_IPV3_OPTION_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv6_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv6_option_impl.hpp new file mode 100644 index 00000000000..17a613b25c4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/ipv6_option_impl.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_IPV6_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_IPV6_OPTION_IMPL_HPP_ + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> + +#include "ip_option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class ipv6_option_impl + : public ip_option_impl { +public: + ipv6_option_impl(); + ipv6_option_impl(const boost::asio::ip::address &_address, + const uint16_t _port, const bool _is_reliable); + virtual ~ipv6_option_impl(); + + bool equals(const option_impl &_other) const; + + const ipv6_address_t & get_address() const; + void set_address(const ipv6_address_t &_address); + + bool is_multicast() const; + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + ipv6_address_t address_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_IPV6_OPTION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/load_balancing_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/load_balancing_option_impl.hpp new file mode 100644 index 00000000000..15fa9179872 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/load_balancing_option_impl.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_LOAD_BALANCING_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_LOAD_BALANCING_OPTION_IMPL_HPP_ + +#include "primitive_types.hpp" +#include "option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class load_balancing_option_impl: public option_impl { +public: + load_balancing_option_impl(); + virtual ~load_balancing_option_impl(); + + bool equals(const option_impl &_other) const; + + priority_t get_priority() const; + void set_priority(priority_t _priority); + + weight_t get_weight() const; + void set_weight(weight_t _weight); + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + priority_t priority_; + weight_t weight_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_LOAD_BALANCING_OPTION_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_element_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_element_impl.hpp new file mode 100644 index 00000000000..2ce979b053f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_element_impl.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_MESSAGE_ELEMENT_IMPL_HPP_ +#define VSOMEIP_V3_SD_MESSAGE_ELEMENT_IMPL_HPP_ + +namespace vsomeip_v3 { +namespace sd { + +class message_impl; + +class message_element_impl { +public: + message_element_impl(); + + message_impl * get_owning_message() const; + void set_owning_message(message_impl *_owner); + +protected: + message_impl *owner_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_MESSAGE_ELEMENT_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_impl.hpp new file mode 100644 index 00000000000..b266f7402cf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/message_impl.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_MESSAGE_IMPL_HPP_ +#define VSOMEIP_V3_SD_MESSAGE_IMPL_HPP_ + +#include <atomic> +#include <memory> +#include <mutex> +#include <vector> + +#include <vsomeip/message.hpp> + +#include "../include/primitive_types.hpp" +#include "../../message/include/message_base_impl.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" + +# if _MSC_VER >= 1300 +/* +* Diamond inheritance is used for the vsomeip::message_base base class. +* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class" +* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class +* by using a common abstract base class. This is also called cross delegation. +*/ +# pragma warning( disable : 4250 ) +# endif + +namespace vsomeip_v3 { +namespace sd { + +class entry_impl; +class eventgroupentry_impl; +class serviceentry_impl; + +class option_impl; +class configuration_option_impl; +class load_balancing_option_impl; +class protection_option_impl; +class selective_option_impl; + +class message_impl + : public vsomeip_v3::message, public vsomeip_v3::message_base_impl { +public: + typedef std::vector<std::shared_ptr<entry_impl>> entries_t; + typedef std::vector<std::shared_ptr<option_impl>> options_t; + struct forced_initial_events_t { + std::shared_ptr<vsomeip_v3::endpoint_definition> target_; + vsomeip_v3::service_t service_; + vsomeip_v3::instance_t instance_; + vsomeip_v3::eventgroup_t eventgroup_; + }; + message_impl(); + virtual ~message_impl(); + + length_t get_length() const; + void set_length(length_t _length); + + length_t get_size() const; + + bool get_reboot_flag() const; + void set_reboot_flag(bool _is_set); + + bool get_unicast_flag() const; + void set_unicast_flag(bool _is_set); + + bool has_entry() const; + bool has_option() const; + + const entries_t & get_entries() const; + const options_t & get_options() const; + + bool add_entry_data(const std::shared_ptr<entry_impl> &_entry, + const std::vector<std::shared_ptr<option_impl> > &_options, + const std::shared_ptr<entry_impl> &_other = nullptr); + + std::shared_ptr<option_impl> find_option( + const std::shared_ptr<option_impl> &_option) const; + + int16_t get_option_index(const std::shared_ptr<option_impl> &_option) const; + std::shared_ptr<option_impl> get_option(int16_t _index) const; + uint32_t get_options_length(); + + std::shared_ptr<payload> get_payload() const; + void set_payload(std::shared_ptr<payload> _payload); + + uint8_t get_check_result() const; + void set_check_result(uint8_t _check_result); + bool is_valid_crc() const; + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + + length_t get_someip_length() const; + + void forced_initial_events_add(forced_initial_events_t _entry); + const std::vector<forced_initial_events_t> forced_initial_events_get(); + + void set_initial_events_required(bool _initial_events_required); + bool initial_events_required() const; + + uid_t get_uid() const; + gid_t get_gid() const; + vsomeip_sec_client_t get_sec_client() const; + std::string get_env() const; + +private: + entry_impl * deserialize_entry(vsomeip_v3::deserializer *_from); + option_impl * deserialize_option(vsomeip_v3::deserializer *_from); + +private: + flags_t flags_; + uint32_t options_length_; + + entries_t entries_; + options_t options_; + + std::mutex message_mutex_; + + std::uint32_t current_message_size_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_MESSAGE_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/option_impl.hpp new file mode 100644 index 00000000000..3c898b6f90f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/option_impl.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_OPTION_IMPL_HPP_ + +#include <cstdint> +#include <memory> + +#include "enumeration_types.hpp" +#include "message_element_impl.hpp" + +namespace vsomeip_v3 { + +class serializer; +class deserializer; + +namespace sd { + +class message_impl; + +class option_impl: public message_element_impl { +public: + option_impl(); + virtual ~option_impl(); + + virtual bool equals(const option_impl &_other) const; + + uint16_t get_length() const; + option_type_e get_type() const; + + inline uint32_t get_size() const { + return static_cast<uint32_t>(length_) + 3; + } + + virtual bool serialize(vsomeip_v3::serializer *_to) const; + virtual bool deserialize(vsomeip_v3::deserializer *_from); + +protected: + uint16_t length_; + option_type_e type_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_OPTION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/primitive_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/primitive_types.hpp new file mode 100644 index 00000000000..682e3f12a12 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/primitive_types.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstdint> + +#ifndef VSOMEIP_V3_SD_PRIMITIVE_TYPES_HPP_ +#define VSOMEIP_V3_SD_PRIMITIVE_TYPES_HPP_ + +namespace vsomeip_v3 { +namespace sd { + +// Load balancing +typedef uint16_t priority_t; +typedef uint16_t weight_t; + +// Protection +typedef uint32_t alive_counter_t; +typedef uint32_t crc_t; + +// +typedef uint8_t flags_t; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_PRIMITIVE_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/protection_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/protection_option_impl.hpp new file mode 100644 index 00000000000..7e34eb50ac9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/protection_option_impl.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_PROTECTION_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_PROTECTION_OPTION_IMPL_HPP_ + +#include "../include/primitive_types.hpp" +#include "../include/option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class protection_option_impl: public option_impl { +public: + protection_option_impl(); + virtual ~protection_option_impl(); + + bool equals(const option_impl &_other) const; + + alive_counter_t get_alive_counter() const; + void set_alive_counter(alive_counter_t _counter); + + crc_t get_crc() const; + void set_crc(crc_t _crc); + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + alive_counter_t counter_; + crc_t crc_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_PROTECTION_OPTION_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/remote_subscription_ack.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/remote_subscription_ack.hpp new file mode 100644 index 00000000000..7b2b63576ec --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/remote_subscription_ack.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_REMOTE_SUBSCRIPTION_ACK_HPP_ +#define VSOMEIP_V3_SD_REMOTE_SUBSCRIPTION_ACK_HPP_ + +#include <memory> +#include <mutex> +#include <set> + +namespace vsomeip_v3 { + +class remote_subscription; + +namespace sd { + +class message_impl; + +class remote_subscription_ack { +public: + remote_subscription_ack(const boost::asio::ip::address &_address); + + // The complete flag signals whether or not all subscribes + // of a message have been inserted. + bool is_complete() const; + void complete(); + + // The done flag signals whether or not all subscribes + // have been processed. + bool is_done() const; + void done(); + + std::vector<std::shared_ptr<message_impl> > get_messages() const; + std::shared_ptr<message_impl> get_current_message() const; + std::shared_ptr<message_impl> add_message(); + + boost::asio::ip::address get_target_address() const; + + bool is_pending() const; + + std::set<std::shared_ptr<remote_subscription> > get_subscriptions() const; + void add_subscription( + const std::shared_ptr<remote_subscription> &_subscription); + bool has_subscription() const; + + std::unique_lock<std::recursive_mutex> get_lock(); + +private: + std::recursive_mutex mutex_; + std::vector<std::shared_ptr<message_impl> > messages_; + bool is_complete_; + bool is_done_; + + const boost::asio::ip::address target_address_; + + std::set<std::shared_ptr<remote_subscription> > subscriptions_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_REMOTE_SUBSCRIPTION_ACK_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/request.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/request.hpp new file mode 100644 index 00000000000..4d4dba03f46 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/request.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_REQUEST_HPP_ +#define VSOMEIP_V3_SD_REQUEST_HPP_ + +#include <memory> + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +class endpoint; + +namespace sd { + +class request { +public: + request(major_version_t _major, minor_version_t _minor, ttl_t _ttl); + + major_version_t get_major() const; + void set_major(major_version_t _major); + + minor_version_t get_minor() const; + void set_minor(minor_version_t _minor); + + ttl_t get_ttl() const; + void set_ttl(ttl_t _ttl); + + uint8_t get_sent_counter() const; + void set_sent_counter(uint8_t _sent_counter); + +private: + major_version_t major_; + minor_version_t minor_; + ttl_t ttl_; + + uint8_t sent_counter_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_REQUEST_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime.hpp new file mode 100644 index 00000000000..fe9f27bfc0d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_RUNTIME_HPP_ +#define VSOMEIP_V3_SD_RUNTIME_HPP_ + +#include <memory> + +namespace vsomeip_v3 { + +class configuration; + +namespace sd { + +class message_impl; +class service_discovery; +class service_discovery_host; + +class runtime { +public: + virtual ~runtime() +#ifndef ANDROID + {} +#else + ; +#endif + + virtual std::shared_ptr<service_discovery> create_service_discovery( + service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) const = 0; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_RUNTIME_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime_impl.hpp new file mode 100644 index 00000000000..1b5bfa4ecab --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/runtime_impl.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_RUNTIME_IMPL_HPP_ +#define VSOMEIP_V3_SD_RUNTIME_IMPL_HPP_ + +#include <vsomeip/plugin.hpp> +#include "runtime.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class runtime_impl + : public runtime, + public plugin_impl<runtime_impl> { +public: + runtime_impl(); + virtual ~runtime_impl(); + + std::shared_ptr<service_discovery> create_service_discovery( + service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) const; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_RUNTIME_IMPL_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/selective_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/selective_option_impl.hpp new file mode 100644 index 00000000000..b4d7bcb3748 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/selective_option_impl.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_SELECTIVE_OPTION_IMPL_HPP +#define VSOMEIP_V3_SD_SELECTIVE_OPTION_IMPL_HPP + +#include <set> + +#include <vsomeip/primitive_types.hpp> + +#include "option_impl.hpp" + +namespace vsomeip_v3 { + +class serializer; +class deserializer; + +namespace sd { + +class selective_option_impl: public option_impl { + +public: + selective_option_impl(); + virtual ~selective_option_impl(); + + bool equals(const option_impl &_other) const; + + std::set<client_t> get_clients() const; + void set_clients(const std::set<client_t> &_clients); + bool add_client(client_t _client); + bool remove_client(client_t _client); + bool has_clients() const; + bool has_client(client_t _client); + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + std::set<client_t> clients_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_SELECTIVE_OPTION_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery.hpp new file mode 100644 index 00000000000..34a33f277f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery.hpp @@ -0,0 +1,84 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_SERVICE_DISCOVERY_HPP_ +#define VSOMEIP_V3_SD_SERVICE_DISCOVERY_HPP_ + +#include <boost/asio/ip/address.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/handler.hpp> +#include "../../routing/include/serviceinfo.hpp" +#include "../../endpoints/include/endpoint.hpp" +#include "../include/service_discovery_host.hpp" + +namespace vsomeip_v3 { + +class configuration; +class eventgroupinfo; + +namespace sd { + +class service_discovery { +public: + virtual ~service_discovery() { + } + + virtual boost::asio::io_context &get_io() = 0; + + virtual void init() = 0; + virtual void start() = 0; + virtual void stop() = 0; + + virtual void request_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, ttl_t _ttl) = 0; + virtual void release_service(service_t _service, instance_t _instance) = 0; + + virtual void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + ttl_t _ttl, client_t _client, + const std::shared_ptr<eventgroupinfo>& _info) = 0; + virtual void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client) = 0; + virtual void unsubscribe_all(service_t _service, instance_t _instance) = 0; + virtual void unsubscribe_all_on_suspend() = 0; + + virtual bool send(bool _is_announcing) = 0; + + virtual void on_message(const byte_t *_data, length_t _length, + const boost::asio::ip::address &_sender, + bool _is_multicast) = 0; + + virtual void + sent_messages(const byte_t* _data, length_t _size, + const boost::asio::ip::address& _remote_address = boost::asio::ip::address()) = 0; + + virtual void on_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint> &_endpoint) = 0; + + virtual void offer_service(const std::shared_ptr<serviceinfo> &_info) = 0; + virtual bool stop_offer_service(const std::shared_ptr<serviceinfo> &_info, bool _send) = 0; + virtual bool send_collected_stop_offers(const std::vector<std::shared_ptr<serviceinfo>> &_infos) = 0; + + virtual void set_diagnosis_mode(const bool _activate) = 0; + + virtual bool get_diagnosis_mode() = 0; + + virtual void update_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription) = 0; + + virtual void register_sd_acceptance_handler( + const sd_acceptance_handler_t &_handler) = 0; + virtual void register_reboot_notification_handler( + const reboot_notification_handler_t &_handler) = 0; + virtual std::recursive_mutex& get_subscribed_mutex() = 0; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_SERVICE_DISCOVERY_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_host.hpp new file mode 100644 index 00000000000..14d2267d84d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_host.hpp @@ -0,0 +1,107 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SERVICE_DISCOVERY_HOST_HPP_ +#define VSOMEIP_V3_SERVICE_DISCOVERY_HOST_HPP_ + +#include <map> +#include <memory> +#include <chrono> + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/io_context.hpp> + +#include "../../routing/include/function_types.hpp" +#include "../../routing/include/types.hpp" + +#include <vsomeip/message.hpp> + +namespace vsomeip_v3 { + +class configuration; +class endpoint; +class endpoint_definition; + +namespace sd { + +class service_discovery_host { +public: + virtual ~service_discovery_host() { + } + + virtual boost::asio::io_context &get_io() = 0; + + virtual std::shared_ptr<endpoint> create_service_discovery_endpoint( + const std::string &_address, uint16_t _port, bool _reliable) = 0; + + virtual services_t get_offered_services() const = 0; + virtual std::shared_ptr<eventgroupinfo> find_eventgroup(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) const = 0; + + virtual bool send(client_t _client, std::shared_ptr<message> _message, + bool _force) = 0; + + virtual bool send_via_sd(const std::shared_ptr<endpoint_definition> &_target, + const byte_t *_data, uint32_t _size, uint16_t _sd_port) = 0; + + virtual void add_routing_info(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, ttl_t _ttl, + const boost::asio::ip::address &_reliable_address, + uint16_t _reliable_port, + const boost::asio::ip::address &_unreliable_address, + uint16_t _unreliable_port) = 0; + + virtual void del_routing_info(service_t _service, instance_t _instance, + bool _has_reliable, bool _has_unreliable) = 0; + + virtual void update_routing_info(std::chrono::milliseconds _elapsed) = 0; + + virtual void on_remote_unsubscribe( + std::shared_ptr<remote_subscription> &_subscription) = 0; + + virtual void on_subscribe_ack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + event_t _event, remote_subscription_id_t _subscription_id) = 0; + + virtual void on_subscribe_ack_with_multicast( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port) = 0; + + virtual std::shared_ptr<endpoint> find_or_create_remote_client( + service_t _service, instance_t _instance, bool _reliable) = 0; + + virtual void expire_subscriptions(const boost::asio::ip::address &_address) = 0; + virtual void expire_subscriptions(const boost::asio::ip::address &_address, + std::uint16_t _port, bool _reliable) = 0; + virtual void expire_services(const boost::asio::ip::address &_address) = 0; + virtual void expire_services(const boost::asio::ip::address &_address, + std::uint16_t _port, bool _reliable) = 0; + + + virtual void on_remote_subscribe( + std::shared_ptr<remote_subscription> &_subscription, + const remote_subscription_callback_t& _callback) = 0; + + virtual void on_subscribe_nack(client_t _client, + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + bool _remove, remote_subscription_id_t _subscription_id) = 0; + + virtual std::chrono::steady_clock::time_point expire_subscriptions(bool _force) = 0; + + virtual std::shared_ptr<serviceinfo> get_offered_service( + service_t _service, instance_t _instance) const = 0; + virtual std::map<instance_t, std::shared_ptr<serviceinfo>> get_offered_service_instances( + service_t _service) const = 0; + + virtual std::set<eventgroup_t> get_subscribed_eventgroups(service_t _service, + instance_t _instance) = 0; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERVICE_DISCOVERY_HOST_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_impl.hpp new file mode 100644 index 00000000000..d07fcb1f733 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/service_discovery_impl.hpp @@ -0,0 +1,517 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_SERVICE_DISCOVERY_IMPL_ +#define VSOMEIP_V3_SD_SERVICE_DISCOVERY_IMPL_ + +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <forward_list> +#include <atomic> +#include <tuple> + +#include <boost/asio/steady_timer.hpp> + +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" +#include "../../routing/include/types.hpp" +#include "../../routing/include/remote_subscription.hpp" + +#include "service_discovery.hpp" +#include "ip_option_impl.hpp" +#include "ipv4_option_impl.hpp" +#include "ipv6_option_impl.hpp" +#include "deserializer.hpp" +#include "message_impl.hpp" + +namespace vsomeip_v3 { + +class endpoint; +class serializer; + +namespace sd { + +class entry_impl; +class eventgroupentry_impl; +class option_impl; +class remote_subscription_ack; +class request; +class serviceentry_impl; +class service_discovery_host; +class subscription; + +typedef std::map<service_t, + std::map<instance_t, + std::shared_ptr<request> + > + > requests_t; + +struct entry_data_t { + std::shared_ptr<entry_impl> entry_; + std::vector<std::shared_ptr<option_impl> > options_; + std::shared_ptr<entry_impl> other_; +}; + +class service_discovery_impl: public service_discovery, + public std::enable_shared_from_this<service_discovery_impl> { +public: + service_discovery_impl(service_discovery_host *_host, + const std::shared_ptr<configuration>& _configuration); + virtual ~service_discovery_impl(); + + boost::asio::io_context &get_io(); + std::recursive_mutex& get_subscribed_mutex(); + + void init(); + void start(); + void stop(); + + void request_service(service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, ttl_t _ttl); + void release_service(service_t _service, instance_t _instance); + + void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, ttl_t _ttl, + client_t _client, const std::shared_ptr<eventgroupinfo>& _info); + void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, client_t _client); + void unsubscribe_all(service_t _service, instance_t _instance); + void unsubscribe_all_on_suspend(); + void remove_subscriptions(service_t _service, instance_t _instance); + + bool send(bool _is_announcing); + + void on_message(const byte_t* _data, length_t _length, const boost::asio::ip::address& _sender, + bool _is_multicast); + + void + sent_messages(const byte_t* _data, length_t _size, + const boost::asio::ip::address& _remote_address = boost::asio::ip::address()); + + void on_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint> &_endpoint); + + void offer_service(const std::shared_ptr<serviceinfo> &_info); + bool stop_offer_service(const std::shared_ptr<serviceinfo> &_info, bool _send); + bool send_collected_stop_offers(const std::vector<std::shared_ptr<serviceinfo>> &_infos); + + void set_diagnosis_mode(const bool _activate); + + bool get_diagnosis_mode(); + + + void update_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription); + + void register_sd_acceptance_handler(const sd_acceptance_handler_t &_handler); + void register_reboot_notification_handler( + const reboot_notification_handler_t &_handler); +private: + std::pair<session_t, bool> get_session(const boost::asio::ip::address &_address); + void increment_session(const boost::asio::ip::address &_address); + + bool is_reboot(const boost::asio::ip::address &_sender, + bool _is_multicast, bool _reboot_flag, session_t _session); + + bool check_session_id_sequence(const boost::asio::ip::address &_sender, + const bool _is_multicast, const session_t &_session, + session_t &_missing_session); + + void insert_find_entries(std::vector<std::shared_ptr<message_impl> > &_messages, + const requests_t &_requests); + void insert_offer_entries(std::vector<std::shared_ptr<message_impl> > &_messages, + const services_t &_services, bool _ignore_phase); + void insert_offer_service(std::vector<std::shared_ptr<message_impl> > &_messages, + const std::shared_ptr<const serviceinfo> &_info); + + entry_data_t create_eventgroup_entry( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const std::shared_ptr<subscription> &_subscription, + reliability_type_e _offer_type); + + void insert_subscription_ack( + const std::shared_ptr<remote_subscription_ack>& _acknowledgement, + const std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, + const std::shared_ptr<endpoint_definition> &_target, + const std::set<client_t> &_clients); + + typedef std::set<std::pair<bool, std::uint16_t>> expired_ports_t; + struct sd_acceptance_state_t { + explicit sd_acceptance_state_t(expired_ports_t& _expired_ports) + : expired_ports_(_expired_ports), + sd_acceptance_required_(false), + accept_entries_(false) { + } + + expired_ports_t& expired_ports_; + bool sd_acceptance_required_; + bool accept_entries_; + }; + + void process_serviceentry(std::shared_ptr<serviceentry_impl>& _entry, + const std::vector<std::shared_ptr<option_impl>>& _options, + bool _unicast_flag, + std::vector<std::shared_ptr<message_impl>>& _resubscribes, + bool _received_via_multicast, + const sd_acceptance_state_t& _sd_ac_state); + void check_sent_offers(const message_impl::entries_t& _entries, + const boost::asio::ip::address& _remote_address) const; + void process_offerservice_serviceentry( + service_t _service, instance_t _instance, major_version_t _major, + minor_version_t _minor, ttl_t _ttl, const boost::asio::ip::address& _reliable_address, + uint16_t _reliable_port, const boost::asio::ip::address& _unreliable_address, + uint16_t _unreliable_port, std::vector<std::shared_ptr<message_impl>>& _resubscribes, + bool _received_via_multicast, const sd_acceptance_state_t& _sd_ac_state); + void send_offer_service( + const std::shared_ptr<const serviceinfo> &_info, service_t _service, + instance_t _instance, major_version_t _major, minor_version_t _minor, + bool _unicast_flag); + + void process_findservice_serviceentry(service_t _service, + instance_t _instance, + major_version_t _major, + minor_version_t _minor, + bool _unicast_flag); + void process_eventgroupentry( + std::shared_ptr<eventgroupentry_impl> &_entry, + const std::vector<std::shared_ptr<option_impl> > &_options, + std::shared_ptr<remote_subscription_ack> &_acknowledgement, + const boost::asio::ip::address &_sender, + bool _is_multicast, + bool _is_stop_subscribe_subscribe, bool _force_initial_events, + const sd_acceptance_state_t& _sd_ac_state); + void handle_eventgroup_subscription( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, ttl_t _ttl, uint8_t _counter, uint16_t _reserved, + const boost::asio::ip::address& _first_address, uint16_t _first_port, + bool _is_first_reliable, const boost::asio::ip::address& _second_address, + uint16_t _second_port, bool _is_second_reliable, + std::shared_ptr<remote_subscription_ack>& _acknowledgement, + bool _is_stop_subscribe_subscribe, bool _force_initial_events, + const std::set<client_t>& _clients, const sd_acceptance_state_t& _sd_ac_state, + const std::shared_ptr<eventgroupinfo>& _info, const boost::asio::ip::address& _sender); + void handle_eventgroup_subscription_ack(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, ttl_t _ttl, uint8_t _counter, + const std::set<client_t> &_clients, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port); + void handle_eventgroup_subscription_nack(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter, + const std::set<client_t> &_clients); + + bool send(const std::vector<std::shared_ptr<message_impl>> &_messages); + bool serialize_and_send( + const std::vector<std::shared_ptr<message_impl>> &_messages, + const boost::asio::ip::address &_address); + + void update_acknowledgement( + const std::shared_ptr<remote_subscription_ack> &_acknowledgement); + + bool is_tcp_connected(service_t _service, + instance_t _instance, + const std::shared_ptr<endpoint_definition>& its_endpoint); + + void start_ttl_timer(int _shift = 0); + void stop_ttl_timer(); + + void check_ttl(const boost::system::error_code &_error); + + void start_subscription_expiration_timer(); + void start_subscription_expiration_timer_unlocked(); + void stop_subscription_expiration_timer(); + void stop_subscription_expiration_timer_unlocked(); + void expire_subscriptions(const boost::system::error_code &_error); + + bool check_ipv4_address(const boost::asio::ip::address& its_address) const; + + bool check_static_header_fields( + const std::shared_ptr<const message> &_message) const; + bool check_layer_four_protocol( + const std::shared_ptr<const ip_option_impl>& _ip_option) const; + + void get_subscription_endpoints(service_t _service, instance_t _instance, + std::shared_ptr<endpoint>& _reliable, + std::shared_ptr<endpoint>& _unreliable) const; + void get_subscription_address(const std::shared_ptr<endpoint> &_reliable, + const std::shared_ptr<endpoint> &_unreliable, + boost::asio::ip::address &_address) const; + + void update_request(service_t _service, instance_t _instance); + + void start_offer_debounce_timer(bool _first_start); + void on_offer_debounce_timer_expired(const boost::system::error_code &_error); + + + void start_find_debounce_timer(bool _first_start); + void on_find_debounce_timer_expired(const boost::system::error_code &_error); + + + void on_repetition_phase_timer_expired( + const boost::system::error_code &_error, + const std::shared_ptr<boost::asio::steady_timer>& _timer, + std::uint8_t _repetition, std::uint32_t _last_delay); + void on_find_repetition_phase_timer_expired( + const boost::system::error_code &_error, + const std::shared_ptr<boost::asio::steady_timer>& _timer, + std::uint8_t _repetition, std::uint32_t _last_delay); + void move_offers_into_main_phase( + const std::shared_ptr<boost::asio::steady_timer> &_timer); + + bool send_stop_offer(const std::shared_ptr<serviceinfo>& _info); + + void start_main_phase_timer(); + void on_main_phase_timer_expired(const boost::system::error_code &_error); + void stop_main_phase_timer(); + + + void send_uni_or_multicast_offerservice( + const std::shared_ptr<const serviceinfo> &_info, + bool _unicast_flag); + bool last_offer_shorter_half_offer_delay_ago(); + void send_unicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info); + void send_multicast_offer_service( + const std::shared_ptr<const serviceinfo>& _info); + + bool check_source_address(const boost::asio::ip::address &its_source_address) const; + + void update_subscription_expiration_timer( + const std::vector<std::shared_ptr<message_impl> > &_messages); + + void remote_subscription_acknowledge( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const std::shared_ptr<remote_subscription> &_subscription); + + bool check_stop_subscribe_subscribe( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t &_options) const; + + bool has_opposite( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t &_options) const; + + bool has_same( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t &_options) const; + + bool is_subscribed( + const std::shared_ptr<eventgroupentry_impl> &_entry, + const message_impl::options_t &_options) const; + + configuration::ttl_factor_t get_ttl_factor( + service_t _service, instance_t _instance, + const configuration::ttl_map_t& _ttl_map) const; + void on_last_msg_received_timer_expired(const boost::system::error_code &_error); + void stop_last_msg_received_timer(); + + reliability_type_e get_remote_offer_type( + service_t _service, instance_t _instance) const; + reliability_type_e get_remote_offer_type( + const std::shared_ptr<subscription> &_subscription) const; + + bool update_remote_offer_type(service_t _service, instance_t _instance, + reliability_type_e _offer_type, + const boost::asio::ip::address& _reliable_address, + std::uint16_t _reliable_port, + const boost::asio::ip::address& _unreliable_address, + std::uint16_t _unreliable_port, bool _received_via_multicast); + void remove_remote_offer_type(service_t _service, instance_t _instance, + const boost::asio::ip::address &_reliable_address, + std::uint16_t _reliable_port, + const boost::asio::ip::address &_unreliable_address, + std::uint16_t _unreliable_port); + void remove_remote_offer_type_by_ip(const boost::asio::ip::address &_address); + void remove_remote_offer_type_by_ip(const boost::asio::ip::address &_address, + std::uint16_t _port, bool _reliable); + + // Returns true if the state changes from unicast -> multicast, false any of the other 3 cases + bool set_offer_multicast_state(service_t _service, instance_t _instance, + reliability_type_e _offer_type, + const boost::asio::ip::address& _reliable_address, + port_t _reliable_port, + const boost::asio::ip::address& _unreliable_address, + std::uint16_t _unreliable_port, bool _received_via_multicast); + + std::shared_ptr<subscription> + create_subscription(major_version_t _major, ttl_t _ttl, + const std::shared_ptr<endpoint>& _reliable, + const std::shared_ptr<endpoint>& _unreliable, + const std::shared_ptr<eventgroupinfo>& _info) const; + + std::shared_ptr<remote_subscription> get_remote_subscription( + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup); + + void send_subscription_ack( + const std::shared_ptr<remote_subscription_ack> &_acknowledgement); + + std::shared_ptr<option_impl> create_ip_option( + const boost::asio::ip::address &_address, uint16_t _port, + bool _is_reliable) const; + + void send_subscription(const std::shared_ptr<subscription> &_subscription, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, const client_t _client); + + void add_entry_data(std::vector<std::shared_ptr<message_impl>> &_messages, + const entry_data_t &_data); + + void add_entry_data_to_remote_subscription_ack_msg( + const std::shared_ptr<remote_subscription_ack>& _acknowledgement, + const entry_data_t &_data); + reliability_type_e get_eventgroup_reliability( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const std::shared_ptr<subscription>& _subscription); + void deserialize_data(const byte_t* _data, const length_t& _size, + std::shared_ptr<message_impl>& _message); + +private: + boost::asio::io_context &io_; + service_discovery_host *host_; + std::shared_ptr<configuration> configuration_; + + boost::asio::ip::address unicast_; + uint16_t port_; + bool reliable_; + std::shared_ptr<endpoint> endpoint_; + + std::shared_ptr<serializer> serializer_; + std::shared_ptr<deserializer> deserializer_; + + requests_t requested_; + std::mutex requested_mutex_; + std::map<service_t, + std::map<instance_t, + std::map<eventgroup_t, + std::shared_ptr<subscription> + > + > + > subscribed_; + std::recursive_mutex subscribed_mutex_; + + std::mutex serialize_mutex_; + std::mutex deserialize_mutex_; + + // Sessions + std::map<boost::asio::ip::address, std::pair<session_t, bool> > sessions_sent_; + std::map<boost::asio::ip::address, + std::tuple<session_t, session_t, bool, bool> > sessions_received_; + std::mutex sessions_received_mutex_; + + // Runtime + std::weak_ptr<runtime> runtime_; + + // TTL handling for services offered by other hosts + std::mutex ttl_timer_mutex_; + boost::asio::steady_timer ttl_timer_; + std::chrono::milliseconds ttl_timer_runtime_; + ttl_t ttl_; + + // TTL handling for subscriptions done by other hosts + std::mutex subscription_expiration_timer_mutex_; + boost::asio::steady_timer subscription_expiration_timer_; + std::chrono::steady_clock::time_point next_subscription_expiration_; + + uint32_t max_message_size_; + + std::chrono::milliseconds initial_delay_; + std::chrono::milliseconds offer_debounce_time_; + std::chrono::milliseconds repetitions_base_delay_; + std::uint8_t repetitions_max_; + std::chrono::milliseconds cyclic_offer_delay_; + std::mutex offer_debounce_timer_mutex_; + boost::asio::steady_timer offer_debounce_timer_; + // this map is used to collect offers while for offer debouncing + std::mutex collected_offers_mutex_; + services_t collected_offers_; + + std::chrono::milliseconds find_debounce_time_; + std::mutex find_debounce_timer_mutex_; + boost::asio::steady_timer find_debounce_timer_; + requests_t collected_finds_; + + // this map contains the offers and their timers currently in repetition phase + std::mutex repetition_phase_timers_mutex_; + std::map<std::shared_ptr<boost::asio::steady_timer>, + services_t> repetition_phase_timers_; + + // this map contains the finds and their timers currently in repetition phase + std::mutex find_repetition_phase_timers_mutex_; + std::map<std::shared_ptr<boost::asio::steady_timer>, + requests_t> find_repetition_phase_timers_; + + std::mutex main_phase_timer_mutex_; + boost::asio::steady_timer main_phase_timer_; + + std::atomic<bool> is_suspended_; + + std::string sd_multicast_; + boost::asio::ip::address sd_multicast_address_; + + boost::asio::ip::address current_remote_address_; + + std::atomic<bool> is_diagnosis_; + + std::mutex pending_remote_subscriptions_mutex_; + std::map<std::shared_ptr<remote_subscription>, + std::shared_ptr<remote_subscription_ack> + > pending_remote_subscriptions_; + std::mutex acknowledgement_mutex_; + + std::mutex response_mutex_; + + configuration::ttl_map_t ttl_factor_offers_; + configuration::ttl_map_t ttl_factor_subscriptions_; + + std::mutex last_msg_received_timer_mutex_; + boost::asio::steady_timer last_msg_received_timer_; + std::chrono::milliseconds last_msg_received_timer_timeout_; + + mutable std::mutex remote_offer_types_mutex_; + std::map<std::pair<service_t, instance_t>, reliability_type_e> remote_offer_types_; + + struct remote_offer_info_t { + std::pair<service_t, instance_t> service_info; + + // The goal of this flag is to handle the SOMEIPSD_00577 requirement + // To do so we will keep track of the last received offer for a given service+instance pair + // The transition between unicast > multicast should be less strict in validations + // and not trigger a [StopSubscribe][Subscribe] + // It shall be mutable to allow the value to be updated within a std::set + mutable bool offer_received_via_multicast; + + remote_offer_info_t(service_t _service, instance_t _instance, + bool _received_via_multicast = true) : + service_info(std::make_pair(_service, _instance)), + offer_received_via_multicast(_received_via_multicast) { } + + // Use the service_info pair as the key for unique values within a std::set + bool operator<(const remote_offer_info_t& other) const { + return service_info < other.service_info; + } + }; + + std::map<boost::asio::ip::address, + std::map<std::pair<bool, std::uint16_t>, std::set<remote_offer_info_t>>> + remote_offers_by_ip_; + + reboot_notification_handler_t reboot_notification_handler_; + sd_acceptance_handler_t sd_acceptance_handler_; + + std::mutex offer_mutex_; + std::mutex check_ttl_mutex_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_SERVICE_DISCOVERY_IMPL_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/serviceentry_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/serviceentry_impl.hpp new file mode 100644 index 00000000000..8e1cf70fdee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/serviceentry_impl.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_SERVICEENTRY_IMPL_HPP +#define VSOMEIP_V3_SD_SERVICEENTRY_IMPL_HPP + +#include "entry_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +class serviceentry_impl: public entry_impl { +public: + serviceentry_impl(); + virtual ~serviceentry_impl(); + + minor_version_t get_minor_version() const; + void set_minor_version(minor_version_t _version); + + bool serialize(vsomeip_v3::serializer *_to) const; + bool deserialize(vsomeip_v3::deserializer *_from); + +private: + minor_version_t minor_version_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_SERVICEENTRY_IMPL_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/subscription.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/subscription.hpp new file mode 100644 index 00000000000..8c1e07473f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/subscription.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_SUBSCRIPTION_HPP_ +#define VSOMEIP_V3_SD_SUBSCRIPTION_HPP_ + +#include <map> +#include <memory> +#include <mutex> +#include <set> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> + +namespace vsomeip_v3 { + +class endpoint; +class eventgroupinfo; + +namespace sd { + +enum class subscription_state_e : uint8_t { + ST_ACKNOWLEDGED = 0x00, + ST_NOT_ACKNOWLEDGED = 0x01, + ST_RESUBSCRIBING = 0x2, + ST_RESUBSCRIBING_NOT_ACKNOWLEDGED = 0x3, + ST_UNKNOWN = 0xFF +}; + +class subscription { +public: + subscription() = default; + ~subscription() = default; + + major_version_t get_major() const; + void set_major(major_version_t _major); + + ttl_t get_ttl() const; + void set_ttl(ttl_t _ttl); + + std::shared_ptr<endpoint> get_endpoint(bool _reliable) const; + void set_endpoint(const std::shared_ptr<endpoint>& _endpoint, bool _reliable); + + bool is_selective() const; + void set_selective(const bool _is_selective); + + subscription_state_e get_state(const client_t _client) const; + void set_state(const client_t _client, subscription_state_e _state); + + bool is_tcp_connection_established() const; + void set_tcp_connection_established(bool _is_established); + + bool is_udp_connection_established() const; + void set_udp_connection_established(bool _is_established); + + bool add_client(const client_t _client); + bool remove_client(const client_t _client); + std::set<client_t> get_clients() const; + bool has_client() const; + bool has_client(const client_t _client) const; + + void set_eventgroupinfo(const std::shared_ptr<eventgroupinfo> _info); + std::weak_ptr<eventgroupinfo> get_eventgroupinfo() const; + +private: + major_version_t major_; + ttl_t ttl_; + + std::shared_ptr<endpoint> reliable_; + std::shared_ptr<endpoint> unreliable_; + + bool is_selective_; + + bool tcp_connection_established_; + bool udp_connection_established_; + + mutable std::mutex clients_mutex_; + std::map<client_t, subscription_state_e> clients_; // client-> is acknowledged? + + std::weak_ptr<eventgroupinfo> eg_info_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SD_SUBSCRIPTION_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/unknown_option_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/unknown_option_impl.hpp new file mode 100644 index 00000000000..d971370a922 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/include/unknown_option_impl.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SD_UNKOWN_OPTION_IMPL_HPP_ +#define VSOMEIP_V3_SD_UNKOWN_OPTION_IMPL_HPP_ + +#include <vector> + +#include "option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +/// @brief An SD Endpoint Option of unknown type. +/// +/// It is meant to allow the deserialization of an option even if its type is unknown. +class unknown_option_impl : public option_impl +{ +public: + /// @brief Constructor. + unknown_option_impl() = default; + + /// @brief Destructor. + ~unknown_option_impl() = default; + + /// @brief Reads the option from the deserializer. + /// + /// @param _from The deserializer that contains the option. + /// @return Whether the deserialization was successful. + virtual bool deserialize(deserializer* _from) override; + + /// @brief The payload of the option as an array of bytes. + /// @return A reference to the payload. + const std::vector<uint8_t>& get_payload() const; + +private: + /// @brief The payload of the option as an array of bytes. + std::vector<uint8_t> payload_; +}; + +} // namespace sd +} // namespace vsomeip_v3 + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/configuration_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/configuration_option_impl.cpp new file mode 100644 index 00000000000..0d50450488c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/configuration_option_impl.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/configuration_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +configuration_option_impl::configuration_option_impl() { + length_ = 2; // always contains "Reserved" and the trailing '\0' + type_ = option_type_e::CONFIGURATION; +} + +configuration_option_impl::~configuration_option_impl() { +} + +bool +configuration_option_impl::equals(const option_impl &_other) const { + bool is_equal(option_impl::equals(_other)); + + if (is_equal) { + const configuration_option_impl &its_other + = dynamic_cast<const configuration_option_impl &>(_other); + is_equal = (configuration_ == its_other.configuration_); + } + + return is_equal; +} + +void configuration_option_impl::add_item(const std::string &_key, + const std::string &_value) { + configuration_[_key] = _value; + length_ = uint16_t(length_ + _key.length() + _value.length() + 2u); // +2 for the '=' and length +} + +void configuration_option_impl::remove_item(const std::string &_key) { + auto it = configuration_.find(_key); + if (it != configuration_.end()) { + length_ = uint16_t(length_ - (it->first.length() + it->second.length() + 2u)); + configuration_.erase(it); + } +} + +std::vector<std::string> configuration_option_impl::get_keys() const { + std::vector < std::string > l_keys; + for (const auto& elem : configuration_) + l_keys.push_back(elem.first); + return l_keys; +} + +std::vector<std::string> configuration_option_impl::get_values() const { + std::vector < std::string > l_values; + for (const auto& elem : configuration_) + l_values.push_back(elem.second); + return l_values; +} + +std::string configuration_option_impl::get_value( + const std::string &_key) const { + std::string l_value(""); + auto l_elem = configuration_.find(_key); + if (l_elem != configuration_.end()) + l_value = l_elem->second; + return l_value; +} + +bool configuration_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful; + std::string configuration_string; + + for (auto i = configuration_.begin(); i != configuration_.end(); ++i) { + char l_length = char(1 + i->first.length() + i->second.length()); + configuration_string.push_back(l_length); + configuration_string.append(i->first); + configuration_string.push_back('='); + configuration_string.append(i->second); + } + configuration_string.push_back('\0'); + + is_successful = option_impl::serialize(_to); + if (is_successful) { + is_successful = _to->serialize( + reinterpret_cast<const uint8_t*>(configuration_string.c_str()), + uint32_t(configuration_string.length())); + } + + return is_successful; +} + +bool configuration_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from); + uint8_t l_itemLength = 0; + std::string l_item(256, 0), l_key, l_value; + + do { + l_itemLength = 0; + l_key.clear(); + l_value.clear(); + l_item.assign(256, '\0'); + + is_successful = is_successful && _from->deserialize(l_itemLength); + if (l_itemLength > 0) { + is_successful = is_successful + && _from->deserialize(l_item, static_cast<std::size_t>(l_itemLength)); + + if (is_successful) { + size_t l_eqPos = l_item.find('='); //SWS_SD_00292 + l_key = l_item.substr(0, l_eqPos); + + //if no "=" is found, no value is present for key (SWS_SD_00466) + if( l_eqPos != std::string::npos ) + l_value = l_item.substr(l_eqPos + 1); + if (configuration_.end() == configuration_.find(l_key)) { + configuration_[l_key] = l_value; + } else { + // TODO: log reason for failing deserialization + is_successful = false; + } + } + } else { + break; + } + } while (is_successful && _from->get_remaining() > 0); + + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/deserializer.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/deserializer.cpp new file mode 100644 index 00000000000..046a523cf3c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/deserializer.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/deserializer.hpp" +#include "../include/message_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +deserializer::deserializer(std::uint32_t _shrink_buffer_threshold) + : vsomeip_v3::deserializer(_shrink_buffer_threshold) { +} + +deserializer::deserializer(uint8_t *_data, std::size_t _length, + std::uint32_t _shrink_buffer_threshold) + : vsomeip_v3::deserializer(_data, _length, _shrink_buffer_threshold) { +} + +deserializer::deserializer(const deserializer &_other) + : vsomeip_v3::deserializer(_other) { +} + +deserializer::~deserializer() { +} + +message_impl * deserializer::deserialize_sd_message() { + message_impl* deserialized_message = new message_impl; + if (0 != deserialized_message) { + if (false == deserialized_message->deserialize(this)) { + delete deserialized_message; + deserialized_message = 0; + } + } + + return deserialized_message; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/entry_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/entry_impl.cpp new file mode 100644 index 00000000000..3873d0a348f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/entry_impl.cpp @@ -0,0 +1,195 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <algorithm> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/entry_impl.hpp" +#include "../include/message_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +// TODO: throw exception if this constructor is used +entry_impl::entry_impl() { + type_ = entry_type_e::UNKNOWN; + major_version_ = 0; + service_ = 0x0; + instance_ = 0x0; + ttl_ = 0x0; + num_options_[0] = 0; + num_options_[1] = 0; + index1_ = 0; + index2_ = 0; +} + +entry_impl::entry_impl(const entry_impl &_entry) { + type_ = _entry.type_; + major_version_ = _entry.major_version_; + service_ = _entry.service_; + instance_ = _entry.instance_; + ttl_ = _entry.ttl_; + num_options_[0] = _entry.num_options_[0]; + num_options_[1] = _entry.num_options_[1]; + index1_ = _entry.index1_; + index2_ = _entry.index2_; +} + +entry_impl::~entry_impl() { +} + +entry_type_e entry_impl::get_type() const { + return type_; +} + +void entry_impl::set_type(entry_type_e _type) { + type_ = _type; +} + +service_t entry_impl::get_service() const { + return service_; +} + +void entry_impl::set_service(service_t _service) { + service_ = _service; +} + +instance_t entry_impl::get_instance() const { + return instance_; +} + +void entry_impl::set_instance(instance_t _instance) { + instance_ = _instance; +} + +major_version_t entry_impl::get_major_version() const { + return major_version_; +} + +void entry_impl::set_major_version(major_version_t _major_version) { + major_version_ = _major_version; +} + +ttl_t entry_impl::get_ttl() const { + return ttl_; +} + +void entry_impl::set_ttl(ttl_t _ttl) { + ttl_ = _ttl; +} + +const std::vector<uint8_t> & entry_impl::get_options(uint8_t _run) const { + static std::vector<uint8_t> invalid_options; + if (_run > 0 && _run <= VSOMEIP_MAX_OPTION_RUN) + return options_[_run - 1]; + + return invalid_options; +} + +void entry_impl::assign_option(const std::shared_ptr<option_impl> &_option) { + int16_t i = get_owning_message()->get_option_index(_option); + if (i > -1 && i < 256) { + uint8_t its_index = static_cast<uint8_t>(i); + if (options_[0].empty() || + options_[0][0] == its_index + 1 || + options_[0][options_[0].size() - 1] + 1 == its_index) { + options_[0].push_back(its_index); + std::sort(options_[0].begin(), options_[0].end()); + num_options_[0]++; + } else if (options_[1].empty() || + options_[1][0] == its_index + 1 || + options_[1][options_[1].size() - 1] + 1 == its_index) { + options_[1].push_back(its_index); + std::sort(options_[1].begin(), options_[1].end()); + num_options_[1]++; + } else { + VSOMEIP_WARNING << "Option is not referenced by entries array, maximum number of endpoint options reached!"; + } + } else { + VSOMEIP_ERROR << "Option could not be found."; + } +} + +bool entry_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = (0 != _to + && _to->serialize(static_cast<uint8_t>(type_))); + + uint8_t index_first_option_run = 0; + if (options_[0].size() > 0) + index_first_option_run = options_[0][0]; + is_successful = is_successful && _to->serialize(index_first_option_run); + + uint8_t index_second_option_run = 0; + if (options_[1].size() > 0) + index_second_option_run = options_[1][0]; + is_successful = is_successful && _to->serialize(index_second_option_run); + + uint8_t number_of_options = uint8_t((((uint8_t) options_[0].size()) << 4) + | (((uint8_t) options_[1].size()) & 0x0F)); + is_successful = is_successful && _to->serialize(number_of_options); + + is_successful = is_successful + && _to->serialize(static_cast<uint16_t>(service_)); + + is_successful = is_successful + && _to->serialize(static_cast<uint16_t>(instance_)); + + return is_successful; +} + +bool entry_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = (0 != _from); + + uint8_t its_type(0); + is_successful = is_successful && _from->deserialize(its_type); + type_ = static_cast<entry_type_e>(its_type); + + is_successful = is_successful && _from->deserialize(index1_); + + is_successful = is_successful && _from->deserialize(index2_); + + uint8_t its_numbers(0); + is_successful = is_successful && _from->deserialize(its_numbers); + + num_options_[0] = uint8_t(its_numbers >> 4); + num_options_[1] = uint8_t(its_numbers & 0xF); + + for (uint16_t i = index1_; i < index1_ + num_options_[0]; ++i) + options_[0].push_back((uint8_t)(i)); + + for (uint16_t i = index2_; i < index2_ + num_options_[1]; ++i) + options_[1].push_back((uint8_t)(i)); + + uint16_t its_id(0); + is_successful = is_successful && _from->deserialize(its_id); + service_ = static_cast<service_t>(its_id); + + is_successful = is_successful && _from->deserialize(its_id); + instance_ = static_cast<instance_t>(its_id); + + return is_successful; +} + +bool entry_impl::is_service_entry() const { + return (type_ <= entry_type_e::REQUEST_SERVICE); +} + +bool entry_impl::is_eventgroup_entry() const { + return (type_ >= entry_type_e::FIND_EVENT_GROUP + && type_ <= entry_type_e::SUBSCRIBE_EVENTGROUP_ACK); +} + +uint8_t entry_impl::get_num_options(uint8_t _run) const { + if (_run < 1 || _run > VSOMEIP_MAX_OPTION_RUN) { + return 0x0; + } + return num_options_[_run-1]; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/eventgroupentry_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/eventgroupentry_impl.cpp new file mode 100644 index 00000000000..f23fd740fb6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/eventgroupentry_impl.cpp @@ -0,0 +1,227 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "../include/constants.hpp" +#include "../include/eventgroupentry_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" +#include "../include/ipv4_option_impl.hpp" +#include "../include/ipv6_option_impl.hpp" +#include "../include/selective_option_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +eventgroupentry_impl::eventgroupentry_impl() : + reserved_(0) { + eventgroup_ = 0xFFFF; + counter_ = 0; +} + +eventgroupentry_impl::eventgroupentry_impl(const eventgroupentry_impl &_entry) + : entry_impl(_entry), + reserved_(0) { + eventgroup_ = _entry.eventgroup_; + counter_ = _entry.counter_; +} + +eventgroupentry_impl::~eventgroupentry_impl() { +} + +eventgroup_t eventgroupentry_impl::get_eventgroup() const { + return eventgroup_; +} + +void eventgroupentry_impl::set_eventgroup(eventgroup_t _eventgroup) { + eventgroup_ = _eventgroup; +} + +uint16_t eventgroupentry_impl::get_reserved() const { + return reserved_; +} + +void eventgroupentry_impl::set_reserved(uint16_t _reserved) { + reserved_ = _reserved; +} + +uint8_t eventgroupentry_impl::get_counter() const { + return counter_; +} + +void eventgroupentry_impl::set_counter(uint8_t _counter) { + counter_ = _counter; +} + +bool eventgroupentry_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = entry_impl::serialize(_to); + is_successful = is_successful && _to->serialize(major_version_); + is_successful = is_successful + && _to->serialize(static_cast<uint32_t>(ttl_), true); + is_successful = is_successful + && _to->serialize(protocol::reserved_word); + is_successful = is_successful + && _to->serialize(static_cast<uint16_t>(eventgroup_)); + + return is_successful; +} + +bool eventgroupentry_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = entry_impl::deserialize(_from); + + uint8_t tmp_major_version(0); + is_successful = is_successful && _from->deserialize(tmp_major_version); + major_version_ = static_cast<major_version_t>(tmp_major_version); + + uint32_t its_ttl(0); + is_successful = is_successful && _from->deserialize(its_ttl, true); + ttl_ = static_cast<ttl_t>(its_ttl); + + is_successful = is_successful && _from->deserialize(reserved_); + + uint16_t its_eventgroup = 0; + is_successful = is_successful && _from->deserialize(its_eventgroup); + eventgroup_ = static_cast<eventgroup_t>(its_eventgroup); + + return is_successful; +} + +bool eventgroupentry_impl::matches(const eventgroupentry_impl& _other, + const message_impl::options_t& _options) const { + if (service_ == _other.service_ + && instance_ == _other.instance_ + && eventgroup_ == _other.eventgroup_ + && major_version_ == _other.major_version_ + && counter_ == _other.counter_) { + + // Check, whether options are identical + if (index1_ == _other.index1_ + && index2_ == _other.index2_ + && num_options_[0] == _other.num_options_[0] + && num_options_[1] == _other.num_options_[1]) { + return true; + } + + // check if entries reference options at different indexes but the + // options itself are identical + // check if number of options referenced is the same + if (num_options_[0] + num_options_[1] + != _other.num_options_[0] + _other.num_options_[1] || + num_options_[0] + num_options_[1] == 0) { + return false; + } + + // read out ip options of current and _other + std::vector<std::shared_ptr<ip_option_impl>> its_options_current; + std::vector<std::shared_ptr<ip_option_impl>> its_options_other; + const std::size_t its_options_size = _options.size(); + for (const auto option_run : {0,1}) { + for (const auto option_index : options_[option_run]) { + if (its_options_size > option_index) { + switch (_options[option_index]->get_type()) { + case option_type_e::IP4_ENDPOINT: + its_options_current.push_back( + std::static_pointer_cast<ipv4_option_impl>( + _options[option_index])); + break; + case option_type_e::IP6_ENDPOINT: + its_options_current.push_back( + std::static_pointer_cast<ipv6_option_impl>( + _options[option_index])); + break; + default: + break; + } + } + } + for (const auto option_index : _other.options_[option_run]) { + if (its_options_size > option_index) { + switch (_options[option_index]->get_type()) { + case option_type_e::IP4_ENDPOINT: + its_options_other.push_back( + std::static_pointer_cast<ipv4_option_impl>( + _options[option_index])); + break; + case option_type_e::IP6_ENDPOINT: + its_options_other.push_back( + std::static_pointer_cast<ipv6_option_impl>( + _options[option_index])); + break; + default: + break; + } + } + } + } + + if (!its_options_current.size() || !its_options_other.size()) { + return false; + } + + // search every option of current in other + for (const auto& c : its_options_current) { + bool found(false); + for (const auto& o : its_options_other) { + if (c->equals(*o)) { + switch (c->get_type()) { + case option_type_e::IP4_ENDPOINT: + if (static_cast<ipv4_option_impl*>(c.get())->get_address() + == static_cast<ipv4_option_impl*>(o.get())->get_address()) { + found = true; + } + break; + case option_type_e::IP6_ENDPOINT: + if (static_cast<ipv6_option_impl*>(c.get())->get_address() + == static_cast<ipv6_option_impl*>(o.get())->get_address()) { + found = true; + } + break; + default: + break; + } + } + if (found) { + break; + } + } + if (!found) { + return false; + } + } + return true; + } + return false; +} + +void eventgroupentry_impl::add_target( + const std::shared_ptr<endpoint_definition> &_target) { + if (_target->is_reliable()) { + target_reliable_ = _target; + } else { + target_unreliable_ = _target; + } +} + +std::shared_ptr<endpoint_definition> eventgroupentry_impl::get_target( + bool _reliable) const { + return _reliable ? target_reliable_ : target_unreliable_; +} + +std::shared_ptr<selective_option_impl> +eventgroupentry_impl::get_selective_option() const { + for (const auto i : {0, 1}) { + for (const auto j : options_[i]) { + auto its_option = std::dynamic_pointer_cast< + selective_option_impl>(owner_->get_option(j)); + if (its_option) + return its_option; + } + } + return nullptr; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ip_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ip_option_impl.cpp new file mode 100644 index 00000000000..197013f9593 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ip_option_impl.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/constants.hpp" +#include "../include/ip_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + + +namespace vsomeip_v3 { +namespace sd { + +ip_option_impl::ip_option_impl() + : protocol_(layer_four_protocol_e::UNKNOWN), port_(0) { +} + +ip_option_impl::ip_option_impl(const uint16_t _port, const bool _is_reliable) + : protocol_(_is_reliable ? + layer_four_protocol_e::TCP : layer_four_protocol_e::UDP), + port_(_port) { +} + +ip_option_impl::~ip_option_impl() { +} + +bool +ip_option_impl::equals(const option_impl &_other) const { + bool is_equal(option_impl::equals(_other)); + + if (is_equal) { + const ip_option_impl &its_other + = dynamic_cast<const ip_option_impl &>(_other); + is_equal = (protocol_ == its_other.protocol_ + && port_ == its_other.port_); + } + return is_equal; +} + +unsigned short ip_option_impl::get_port() const { + return port_; +} + +void ip_option_impl::set_port(unsigned short _port) { + port_ = _port; +} + +layer_four_protocol_e ip_option_impl::get_layer_four_protocol() const { + return protocol_; +} + +void ip_option_impl::set_layer_four_protocol( + layer_four_protocol_e _protocol) { + protocol_ = _protocol; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv4_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv4_option_impl.cpp new file mode 100644 index 00000000000..f2eef958a9f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv4_option_impl.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/constants.hpp> + +#include "../include/constants.hpp" +#include "../include/defines.hpp" +#include "../include/ipv4_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +ipv4_option_impl::ipv4_option_impl() + : address_({0}) { + length_ = (1 + 4 + 1 + 1 + 2); +} + +ipv4_option_impl::ipv4_option_impl(const boost::asio::ip::address &_address, + const uint16_t _port, const bool _is_reliable) + : ip_option_impl(_port, _is_reliable), address_(_address.to_v4().to_bytes()) { + type_ = (_address.is_multicast() ? + option_type_e::IP4_MULTICAST : option_type_e::IP4_ENDPOINT); + length_ = (1 + 4 + 1 + 1 + 2); +} + +ipv4_option_impl::~ipv4_option_impl() { +} + +bool +ipv4_option_impl::equals(const option_impl &_other) const { + bool is_equal(ip_option_impl::equals(_other)); + if (is_equal) { + const ipv4_option_impl &its_other + = dynamic_cast<const ipv4_option_impl &>(_other); + is_equal = (address_ == its_other.address_); + } + return is_equal; +} + +const ipv4_address_t & ipv4_option_impl::get_address() const { + return address_; +} + +void ipv4_option_impl::set_address(const ipv4_address_t &_address) { + address_ = _address; + + boost::asio::ip::address_v4 its_address(_address); + type_ = (its_address.is_multicast() ? + option_type_e::IP4_MULTICAST : option_type_e::IP4_ENDPOINT); +} + +bool ipv4_option_impl::is_multicast() const { + return (type_ == option_type_e::IP4_MULTICAST); +} + +bool ipv4_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = option_impl::serialize(_to); + _to->serialize(&address_[0], uint32_t(address_.size())); + _to->serialize(protocol::reserved_byte); + _to->serialize(static_cast<uint8_t>(protocol_)); + _to->serialize(port_); + return is_successful; +} + +bool ipv4_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from) + && length_ == VSOMEIP_SD_IPV4_OPTION_LENGTH; + uint8_t its_reserved(static_cast<std::uint8_t>(layer_four_protocol_e::UNKNOWN)); + _from->deserialize(address_.data(), 4); + _from->deserialize(its_reserved); + _from->deserialize(its_reserved); + switch (static_cast<layer_four_protocol_e>(its_reserved)) { + case layer_four_protocol_e::TCP: + case layer_four_protocol_e::UDP: + protocol_ = static_cast<layer_four_protocol_e>(its_reserved); + break; + default: + protocol_ = layer_four_protocol_e::UNKNOWN; + } + _from->deserialize(port_); + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv6_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv6_option_impl.cpp new file mode 100644 index 00000000000..54e751dea58 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/ipv6_option_impl.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/constants.hpp" +#include "../include/defines.hpp" +#include "../include/ipv6_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +ipv6_option_impl::ipv6_option_impl() + : address_({0}) { + length_ = (1 + 16 + 1 + 1 + 2); +} + +ipv6_option_impl::ipv6_option_impl(const boost::asio::ip::address &_address, + const uint16_t _port, const bool _is_reliable) + : ip_option_impl(_port, _is_reliable), address_(_address.to_v6().to_bytes()) { + type_ = (_address.is_multicast() ? + option_type_e::IP6_MULTICAST : option_type_e::IP6_ENDPOINT); + length_ = (1 + 16 + 1 + 1 + 2); +} + +ipv6_option_impl::~ipv6_option_impl() { +} + +bool +ipv6_option_impl::equals(const option_impl &_other) const { + bool is_equal(ip_option_impl::equals(_other)); + + if (is_equal) { + const ipv6_option_impl &its_other + = dynamic_cast<const ipv6_option_impl &>(_other); + is_equal = (address_ == its_other.address_); + } + + return is_equal; +} + +const ipv6_address_t & ipv6_option_impl::get_address() const { + return address_; +} + +void ipv6_option_impl::set_address(const ipv6_address_t &_address) { + address_ = _address; + + boost::asio::ip::address_v6 its_address(_address); + type_ = (its_address.is_multicast() ? + option_type_e::IP6_MULTICAST : option_type_e::IP6_ENDPOINT); +} + +bool ipv6_option_impl::is_multicast() const { + return (type_ == option_type_e::IP6_MULTICAST); +} + +bool ipv6_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = option_impl::serialize(_to); + _to->serialize(&address_[0], uint32_t(address_.size())); + _to->serialize(protocol::reserved_byte); + _to->serialize(static_cast<uint8_t>(protocol_)); + _to->serialize(port_); + return is_successful; +} + +bool ipv6_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from) + && length_ == VSOMEIP_SD_IPV6_OPTION_LENGTH; + uint8_t its_reserved(static_cast<std::uint8_t>(layer_four_protocol_e::UNKNOWN)); + _from->deserialize(address_.data(), 16); + _from->deserialize(its_reserved); + _from->deserialize(its_reserved); + switch (static_cast<layer_four_protocol_e>(its_reserved)) { + case layer_four_protocol_e::TCP: + case layer_four_protocol_e::UDP: + protocol_ = static_cast<layer_four_protocol_e>(its_reserved); + break; + default: + protocol_ = layer_four_protocol_e::UNKNOWN; + } + _from->deserialize(port_); + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/load_balancing_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/load_balancing_option_impl.cpp new file mode 100644 index 00000000000..096b9889f0a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/load_balancing_option_impl.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/load_balancing_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +load_balancing_option_impl::load_balancing_option_impl() { + length_ = 1 + 2 + 2; + type_ = option_type_e::LOAD_BALANCING; + priority_ = 0; + weight_ = 0; +} + +load_balancing_option_impl::~load_balancing_option_impl() { +} + +bool +load_balancing_option_impl::equals(const option_impl &_other) const { + bool is_equal(option_impl::equals(_other)); + + if (is_equal) { + const load_balancing_option_impl &its_other + = dynamic_cast<const load_balancing_option_impl &>(_other); + is_equal = (priority_ == its_other.priority_ + && weight_ == its_other.weight_); + } + + return is_equal; +} + +priority_t load_balancing_option_impl::get_priority() const { + return priority_; +} + +void load_balancing_option_impl::set_priority(priority_t _priority) { + priority_ = _priority; +} + +weight_t load_balancing_option_impl::get_weight() const { + return weight_; +} + +void load_balancing_option_impl::set_weight(weight_t _weight) { + weight_ = _weight; +} + +bool load_balancing_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = option_impl::serialize(_to); + is_successful = is_successful + && _to->serialize(static_cast<uint16_t>(priority_)); + is_successful = is_successful + && _to->serialize(static_cast<uint16_t>(weight_)); + return is_successful; +} + +bool load_balancing_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from); + + uint16_t tmp_priority = 0; + is_successful = is_successful && _from->deserialize(tmp_priority); + priority_ = static_cast<priority_t>(tmp_priority); + + uint16_t tmp_weight = 0; + is_successful = is_successful && _from->deserialize(tmp_weight); + weight_ = static_cast<weight_t>(tmp_weight); + + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_element_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_element_impl.cpp new file mode 100644 index 00000000000..afdb5079008 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_element_impl.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/message_element_impl.hpp" + +namespace vsomeip_v3 { +namespace sd { + +message_element_impl::message_element_impl() { + owner_ = 0; +} + +message_impl * message_element_impl::get_owning_message() const { + return owner_; +} + +void message_element_impl::set_owning_message(message_impl *_owner) { + owner_ = _owner; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_impl.cpp new file mode 100644 index 00000000000..cec09a10a64 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/message_impl.cpp @@ -0,0 +1,443 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <typeinfo> + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +// internal[_android.hpp] must be included before defines.hpp +#ifdef ANDROID +#include "../../configuration/include/internal_android.hpp" +#else +#include "../../configuration/include/internal.hpp" +#endif // ANDROID + +#include "../include/constants.hpp" +#include "../include/defines.hpp" +#include "../include/eventgroupentry_impl.hpp" +#include "../include/serviceentry_impl.hpp" +#include "../include/configuration_option_impl.hpp" +#include "../include/ipv4_option_impl.hpp" +#include "../include/ipv6_option_impl.hpp" +#include "../include/load_balancing_option_impl.hpp" +#include "../include/protection_option_impl.hpp" +#include "../include/selective_option_impl.hpp" +#include "../include/message_impl.hpp" +#include "../include/unknown_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/payload_impl.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +message_impl::message_impl() : + flags_(0x0), + options_length_(0x0), + current_message_size_(VSOMEIP_SOMEIP_SD_EMPTY_MESSAGE_SIZE) { + header_.service_ = VSOMEIP_SD_SERVICE; + header_.instance_ = VSOMEIP_SD_INSTANCE; + header_.method_ = VSOMEIP_SD_METHOD; + header_.client_ = VSOMEIP_SD_CLIENT; + // session must be set dynamically + header_.protocol_version_ = protocol_version; + header_.interface_version_ = interface_version; + header_.type_ = message_type; + header_.code_ = return_code; + + set_unicast_flag(true); +} + +message_impl::~message_impl() { +} + +length_t message_impl::get_length() const { + length_t current_length = VSOMEIP_SOMEIP_SD_DATA_SIZE; + if( entries_.size()) { + current_length += VSOMEIP_SOMEIP_SD_ENTRY_LENGTH_SIZE; + current_length += uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE); + } + + current_length += VSOMEIP_SOMEIP_SD_OPTION_LENGTH_SIZE; + if(options_.size()) { + for (size_t i = 0; i < options_.size(); ++i) { + current_length += static_cast<length_t>(options_[i]->get_length() + + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE); + } + } + return current_length; +} + +length_t message_impl::get_size() const { + return current_message_size_; +} + +#define VSOMEIP_REBOOT_FLAG 0x80 + +bool message_impl::get_reboot_flag() const { + return ((flags_ & VSOMEIP_REBOOT_FLAG) != 0); +} + +void message_impl::set_reboot_flag(bool _is_set) { + if (_is_set) + flags_ |= flags_t(VSOMEIP_REBOOT_FLAG); + else + flags_ &= flags_t(~VSOMEIP_REBOOT_FLAG); +} + +#define VSOMEIP_UNICAST_FLAG 0x40 + +bool message_impl::get_unicast_flag() const { + return ((flags_ & VSOMEIP_UNICAST_FLAG) != 0); +} + +void message_impl::set_unicast_flag(bool _is_set) { + if (_is_set) + flags_ |= flags_t(VSOMEIP_UNICAST_FLAG); + else + flags_ &= flags_t(~VSOMEIP_UNICAST_FLAG); +} + +bool +message_impl::add_entry_data(const std::shared_ptr<entry_impl> &_entry, + const std::vector<std::shared_ptr<option_impl> > &_options, + const std::shared_ptr<entry_impl> &_other) { + std::uint32_t its_entry_size = VSOMEIP_SOMEIP_SD_ENTRY_SIZE; + std::map<const std::shared_ptr<option_impl>, bool> its_options; + + if (_other) { + its_entry_size += VSOMEIP_SOMEIP_SD_ENTRY_SIZE; + } + + // TODO: Check whether it is possible to express the options + // by the two runs. If there are more than two options, it + // might be necessary to copy an option, which then increases + // the size... + + for (const std::shared_ptr<option_impl> &its_option : _options) { + const auto its_existing_option = find_option(its_option); + if (!its_existing_option) { + its_entry_size += its_option->get_size(); + its_options[its_option] = true; + } else { + its_options[its_existing_option] = false; + } + } + + if (current_message_size_ + its_entry_size > VSOMEIP_MAX_UDP_SD_PAYLOAD) + return false; + + entries_.push_back(_entry); + _entry->set_owning_message(this); + for (const auto &its_option : its_options) { + if (its_option.second) { + options_.push_back(its_option.first); + its_option.first->set_owning_message(this); + } + _entry->assign_option(its_option.first); + } + + if (_other) { + entries_.push_back(_other); + _other->set_owning_message(this); + for (const auto &its_option : its_options) { + _other->assign_option(its_option.first); + } + } + + current_message_size_ += its_entry_size; + + return true; +} + +bool +message_impl::has_entry() const { + return (0 < entries_.size()); +} + +bool +message_impl::has_option() const { + return (0 < options_.size()); +} + +void message_impl::set_length(length_t _length) { + (void)_length; +} + +const message_impl::entries_t & message_impl::get_entries() const { + return entries_; +} + +const message_impl::options_t & message_impl::get_options() const { + return options_; +} + +std::shared_ptr<option_impl> +message_impl::find_option(const std::shared_ptr<option_impl> &_option) const { + for (auto its_option : options_) { + if (its_option->equals(*_option)) + return its_option; + } + return nullptr; +} + +int16_t message_impl::get_option_index( + const std::shared_ptr<option_impl> &_option) const { + int16_t i = 0; + + while (i < int16_t(options_.size())) { + if (options_[static_cast<options_t::size_type>(i)] == _option) + return i; + i++; + } + return -1; +} + +std::shared_ptr<option_impl> +message_impl::get_option(int16_t _index) const { + if (_index > -1) { + size_t its_index = static_cast<size_t>(_index); + if (its_index < options_.size()) + return options_[its_index]; + } + return nullptr; +} + +uint32_t message_impl::get_options_length() { + return options_length_; +} + +std::shared_ptr<payload> message_impl::get_payload() const { + return std::make_shared<payload_impl>(); +} + +void message_impl::set_payload(std::shared_ptr<payload> _payload) { + (void)_payload; +} + +uint8_t message_impl::get_check_result() const { + return 1; +} +void message_impl::set_check_result(uint8_t _check_result) { + (void)_check_result; +} + +bool message_impl::is_valid_crc() const { + return false; +} + +bool message_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = header_.serialize(_to); + is_successful = is_successful && _to->serialize(flags_); + is_successful = is_successful + && _to->serialize(protocol::reserved_long, true); + + uint32_t entries_length = uint32_t(entries_.size() * VSOMEIP_SOMEIP_SD_ENTRY_SIZE); + is_successful = is_successful && _to->serialize(entries_length); + + for (const auto& its_entry : entries_) + is_successful = is_successful && its_entry && its_entry->serialize(_to); + + uint32_t options_length = 0; + for (const auto& its_option : options_) + options_length += its_option ? static_cast<uint32_t>(its_option->get_length() + + VSOMEIP_SOMEIP_SD_OPTION_HEADER_SIZE) : 0; + is_successful = is_successful && _to->serialize(options_length); + + for (const auto& its_option : options_) + is_successful = is_successful && its_option && its_option->serialize(_to); + + return is_successful; +} + +bool message_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful; + bool option_is_successful(true); + + // header + is_successful = header_.deserialize(_from); + + // flags + is_successful = is_successful && _from->deserialize(flags_); + + // reserved + uint32_t reserved; + is_successful = is_successful && _from->deserialize(reserved, true); + + // entries + uint32_t entries_length = 0; + is_successful = is_successful && _from->deserialize(entries_length); + + // backup the current remaining length + uint32_t save_remaining = uint32_t(_from->get_remaining()); + if (!is_successful) { + // couldn't deserialize entries length + return is_successful; + } else if (entries_length > save_remaining) { + // not enough data available to deserialize entries array + is_successful = false; + return is_successful; + } + + // set remaining bytes to length of entries array + _from->set_remaining(entries_length); + + // deserialize the entries + while (is_successful && _from->get_remaining()) { + std::shared_ptr < entry_impl > its_entry(deserialize_entry(_from)); + if (its_entry) { + entries_.push_back(its_entry); + } else { + is_successful = false; + } + } + + // set length to remaining bytes after entries array + _from->set_remaining(save_remaining - entries_length); + + // Don't try to deserialize options if there aren't any + if(_from->get_remaining() == 0) { + return is_successful; + } + + // deserialize the options + is_successful = is_successful && _from->deserialize(options_length_); + + // check if there is unreferenced data behind the last option and discard it + if(_from->get_remaining() > options_length_) { + _from->set_remaining(options_length_); + } + + while (option_is_successful && _from->get_remaining()) { + std::shared_ptr < option_impl > its_option(deserialize_option(_from)); + if (its_option) { + options_.push_back(its_option); + } else { + option_is_successful = false; + } + } + current_message_size_ = 0; + return is_successful; +} + +entry_impl * message_impl::deserialize_entry(vsomeip_v3::deserializer *_from) { + entry_impl *deserialized_entry = 0; + uint8_t tmp_entry_type; + + if (_from->look_ahead(0, tmp_entry_type)) { + entry_type_e deserialized_entry_type = + static_cast<entry_type_e>(tmp_entry_type); + + switch (deserialized_entry_type) { + case entry_type_e::FIND_SERVICE: + case entry_type_e::OFFER_SERVICE: + //case entry_type_e::STOP_OFFER_SERVICE: + case entry_type_e::REQUEST_SERVICE: + deserialized_entry = new serviceentry_impl; + break; + + case entry_type_e::FIND_EVENT_GROUP: + case entry_type_e::PUBLISH_EVENTGROUP: + //case entry_type_e::STOP_PUBLISH_EVENTGROUP: + case entry_type_e::SUBSCRIBE_EVENTGROUP: + //case entry_type_e::STOP_SUBSCRIBE_EVENTGROUP: + case entry_type_e::SUBSCRIBE_EVENTGROUP_ACK: + //case entry_type_e::STOP_SUBSCRIBE_EVENTGROUP_ACK: + deserialized_entry = new eventgroupentry_impl; + break; + + default: + break; + }; + + // deserialize object + if (0 != deserialized_entry) { + deserialized_entry->set_owning_message(this); + if (!deserialized_entry->deserialize(_from)) { + delete deserialized_entry; + deserialized_entry = 0; + }; + } + } + + return deserialized_entry; +} + +option_impl * message_impl::deserialize_option(vsomeip_v3::deserializer *_from) { + option_impl *deserialized_option = 0; + uint8_t tmp_option_type; + + if (_from->look_ahead(2, tmp_option_type)) { + + option_type_e deserialized_option_type = + static_cast<option_type_e>(tmp_option_type); + + switch (deserialized_option_type) { + + case option_type_e::CONFIGURATION: + deserialized_option = new configuration_option_impl; + break; + case option_type_e::LOAD_BALANCING: + deserialized_option = new load_balancing_option_impl; + break; + case option_type_e::PROTECTION: + deserialized_option = new protection_option_impl; + break; + case option_type_e::IP4_ENDPOINT: + case option_type_e::IP4_MULTICAST: + deserialized_option = new ipv4_option_impl; + break; + case option_type_e::IP6_ENDPOINT: + case option_type_e::IP6_MULTICAST: + deserialized_option = new ipv6_option_impl; + break; + case option_type_e::SELECTIVE: + deserialized_option = new selective_option_impl; + break; + + default: + deserialized_option = new unknown_option_impl(); + break; + }; + + // deserialize object + if (0 != deserialized_option + && !deserialized_option->deserialize(_from)) { + delete deserialized_option; + deserialized_option = 0; + }; + } + + return deserialized_option; +} + +length_t message_impl::get_someip_length() const { + return header_.length_; +} + +uid_t message_impl::get_uid() const { + return ANY_UID; +} + +gid_t message_impl::get_gid() const { + return ANY_GID; +} + +vsomeip_sec_client_t message_impl::get_sec_client() const { + static vsomeip_sec_client_t its_dummy_sec_client{ + ANY_UID, ANY_GID, 0, VSOMEIP_SEC_PORT_UNUSED + }; + + return its_dummy_sec_client; +} + +std::string message_impl::get_env() const { + return (""); +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/option_impl.cpp new file mode 100644 index 00000000000..32aaac2f2b7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/option_impl.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/constants.hpp" +#include "../include/option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +option_impl::option_impl() : + length_(0), + type_(option_type_e::UNKNOWN) { +} + +option_impl::~option_impl() { +} + +bool +option_impl::equals(const option_impl &_other) const { + return (type_ == _other.get_type() && length_ == _other.get_length()); +} + +uint16_t option_impl::get_length() const { + return length_; +} + +option_type_e option_impl::get_type() const { + return type_; +} + +bool option_impl::serialize(vsomeip_v3::serializer *_to) const { + return (0 != _to && _to->serialize(length_) + && _to->serialize(static_cast<uint8_t>(type_)) + && _to->serialize(protocol::reserved_byte)); +} + +bool option_impl::deserialize(vsomeip_v3::deserializer *_from) { + uint8_t its_type, reserved; + bool l_result = (0 != _from && _from->deserialize(length_) + && _from->deserialize(its_type) && _from->deserialize(reserved)); + + if (l_result) { + switch(static_cast<option_type_e>(its_type)) { + case option_type_e::CONFIGURATION: + case option_type_e::LOAD_BALANCING: + case option_type_e::PROTECTION: + case option_type_e::IP4_ENDPOINT: + case option_type_e::IP6_ENDPOINT: + case option_type_e::IP4_MULTICAST: + case option_type_e::IP6_MULTICAST: + case option_type_e::SELECTIVE: + type_ = static_cast<option_type_e>(its_type); + break; + default: + type_ = option_type_e::UNKNOWN; + } + } + + return l_result; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/protection_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/protection_option_impl.cpp new file mode 100644 index 00000000000..6d79860a3a3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/protection_option_impl.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/protection_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +protection_option_impl::protection_option_impl() { + length_ = 1 + 4 + 4; + type_ = option_type_e::PROTECTION; + counter_ = 0; + crc_ = 0; +} + +protection_option_impl::~protection_option_impl() { +} + +bool +protection_option_impl::equals(const option_impl &_other) const { + bool is_equal(option_impl::equals(_other)); + + if (is_equal) { + const protection_option_impl &its_other + = dynamic_cast<const protection_option_impl &>(_other); + is_equal = (counter_ == its_other.counter_ + && crc_ == its_other.crc_); + } + + return is_equal; +} + +alive_counter_t protection_option_impl::get_alive_counter() const { + return counter_; +} + +void protection_option_impl::set_alive_counter(alive_counter_t _counter) { + counter_ = _counter; +} + +crc_t protection_option_impl::get_crc() const { + return crc_; +} + +void protection_option_impl::set_crc(crc_t _crc) { + crc_ = _crc; +} + +bool protection_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = option_impl::serialize(_to); + is_successful = is_successful + && _to->serialize(static_cast<uint32_t>(counter_)); + is_successful = is_successful + && _to->serialize(static_cast<uint32_t>(crc_)); + return is_successful; +} + +bool protection_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from); + + uint32_t its_alive_counter = 0; + is_successful = is_successful && _from->deserialize(its_alive_counter); + counter_ = static_cast<alive_counter_t>(its_alive_counter); + + uint32_t its_crc = 0; + is_successful = is_successful && _from->deserialize(its_crc); + crc_ = static_cast<crc_t>(its_crc); + + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/remote_subscription_ack.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/remote_subscription_ack.cpp new file mode 100644 index 00000000000..45fa0576bd2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/remote_subscription_ack.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/message_impl.hpp" +#include "../include/remote_subscription_ack.hpp" +#include "../../routing/include/remote_subscription.hpp" + +namespace vsomeip_v3 { +namespace sd { + +remote_subscription_ack::remote_subscription_ack(const boost::asio::ip::address &_address) + : is_complete_(false), + is_done_(false), + target_address_(_address) { + messages_.push_back(std::make_shared<message_impl>()); +} + +bool +remote_subscription_ack::is_complete() const { + return is_complete_; +} + +void +remote_subscription_ack::complete() { + is_complete_ = true; +} + +bool +remote_subscription_ack::is_done() const { + return is_done_; +} + +void +remote_subscription_ack::done() { + is_done_ = true; +} + +std::vector<std::shared_ptr<message_impl> > +remote_subscription_ack::get_messages() const { + return messages_; +} + +std::shared_ptr<message_impl> remote_subscription_ack::get_current_message() const { + return messages_.back(); +} + +std::shared_ptr<message_impl> remote_subscription_ack::add_message() { + messages_.emplace_back(std::make_shared<message_impl>()); + return messages_.back(); +} + +boost::asio::ip::address +remote_subscription_ack::get_target_address() const { + return target_address_; +} + +bool +remote_subscription_ack::is_pending() const { + for (const auto& its_subscription : subscriptions_) { + if (its_subscription->is_pending() + && its_subscription->get_answers() != 0) { + return true; + } + } + return false; +} + +std::set<std::shared_ptr<remote_subscription> > +remote_subscription_ack::get_subscriptions() const { + return subscriptions_; +} + +void +remote_subscription_ack::add_subscription( + const std::shared_ptr<remote_subscription> &_subscription) { + subscriptions_.insert(_subscription); +} + +bool +remote_subscription_ack::has_subscription() const { + return (0 < subscriptions_.size()); +} + +std::unique_lock<std::recursive_mutex> remote_subscription_ack::get_lock() { + return std::unique_lock<std::recursive_mutex>(mutex_); +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/request.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/request.cpp new file mode 100644 index 00000000000..ee6b10bd00d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/request.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/request.hpp" + +namespace vsomeip_v3 { +namespace sd { + +request::request(major_version_t _major, minor_version_t _minor, ttl_t _ttl) + : major_(_major), minor_(_minor), ttl_(_ttl), sent_counter_(0) { +} + +major_version_t request::get_major() const { + return major_; +} + +void request::set_major(major_version_t _major) { + major_ = _major; +} + +minor_version_t request::get_minor() const { + return minor_; +} + +void request::set_minor(minor_version_t _minor) { + minor_ = _minor; +} + +ttl_t request::get_ttl() const { + return ttl_; +} + +void request::set_ttl(ttl_t _ttl) { + ttl_ = _ttl; +} + +uint8_t request::get_sent_counter() const { + return sent_counter_; +} + +void request::set_sent_counter(uint8_t _sent_counter) { + sent_counter_ = _sent_counter; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/runtime_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/runtime_impl.cpp new file mode 100644 index 00000000000..f0fa456e021 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/runtime_impl.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/defines.hpp> +#include <vsomeip/message.hpp> + +#include "../include/constants.hpp" +#include "../include/defines.hpp" +#include "../include/message_impl.hpp" +#include "../include/runtime_impl.hpp" +#include "../include/service_discovery_impl.hpp" + +VSOMEIP_PLUGIN(vsomeip_v3::sd::runtime_impl) + +namespace vsomeip_v3 { +namespace sd { + +runtime_impl::runtime_impl() + : plugin_impl("vsomeip SD plug-in", 1, plugin_type_e::SD_RUNTIME_PLUGIN) { +} + +runtime_impl::~runtime_impl() { +} + +std::shared_ptr<service_discovery> +runtime_impl::create_service_discovery(service_discovery_host *_host, + std::shared_ptr<configuration> _configuration) const { + return std::make_shared<service_discovery_impl>(_host, _configuration); +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/selective_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/selective_option_impl.cpp new file mode 100644 index 00000000000..ab5a38bb6e3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/selective_option_impl.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2018-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/selective_option_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +selective_option_impl::selective_option_impl() { + length_ = 1; // always contains "Reserved" + type_ = option_type_e::SELECTIVE; +} + +selective_option_impl::~selective_option_impl() { +} + +bool +selective_option_impl::equals(const option_impl &_other) const { + bool is_equal(option_impl::equals(_other)); + if (is_equal) { + const selective_option_impl &its_other + = dynamic_cast<const selective_option_impl &>(_other); + is_equal = (clients_ == its_other.clients_); + } + return is_equal; +} + +std::set<client_t> selective_option_impl::get_clients() const { + std::set<client_t> its_clients(clients_); + return its_clients; +} + +void selective_option_impl::set_clients(const std::set<client_t> &_clients) { + clients_ = _clients; + length_ = uint16_t(1 + clients_.size() * sizeof(client_t)); +} + +bool selective_option_impl::add_client(client_t _client) { + auto its_result = clients_.insert(_client); + length_ = uint16_t(1 + clients_.size() * sizeof(client_t)); + return its_result.second; +} + +bool selective_option_impl::remove_client(client_t _client) { + auto its_size = clients_.size(); + clients_.erase(_client); + length_ = uint16_t(1 + clients_.size() * sizeof(client_t)); + return (clients_.size() < its_size); +} + +bool selective_option_impl::has_clients() const { + return !clients_.empty(); +} + +bool selective_option_impl::has_client(client_t _client) { + auto find_client = clients_.find(_client); + return (find_client != clients_.end()); +} + +bool selective_option_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = option_impl::serialize(_to); + if (is_successful) { + for (auto &its_client : clients_) + _to->serialize(its_client); + } + return is_successful; +} + +bool selective_option_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = option_impl::deserialize(_from); + if (is_successful) { + uint16_t i = 1; + while (i < length_) { + client_t its_client; + is_successful = _from->deserialize(its_client); + + clients_.insert(its_client); + i = uint16_t(i + sizeof(client_t)); + } + } + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/service_discovery_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/service_discovery_impl.cpp new file mode 100644 index 00000000000..768384b218b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/service_discovery_impl.cpp @@ -0,0 +1,4001 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/constants.hpp> + +#include <chrono> +#include <iomanip> +#include <forward_list> +#include <random> +#include <thread> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/constants.hpp" +#include "../include/defines.hpp" +#include "../include/deserializer.hpp" +#include "../include/enumeration_types.hpp" +#include "../include/eventgroupentry_impl.hpp" +#include "../include/ipv4_option_impl.hpp" +#include "../include/ipv6_option_impl.hpp" +#include "../include/selective_option_impl.hpp" +#include "../include/message_impl.hpp" +#include "../include/remote_subscription_ack.hpp" +#include "../include/request.hpp" +#include "../include/runtime.hpp" +#include "../include/service_discovery_host.hpp" +#include "../include/service_discovery_impl.hpp" +#include "../include/serviceentry_impl.hpp" +#include "../include/subscription.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../endpoints/include/endpoint.hpp" +#include "../../endpoints/include/client_endpoint.hpp" +#include "../../endpoints/include/endpoint_definition.hpp" +#include "../../endpoints/include/tcp_server_endpoint_impl.hpp" +#include "../../endpoints/include/udp_server_endpoint_impl.hpp" +#include "../../message/include/serializer.hpp" +#include "../../plugin/include/plugin_manager_impl.hpp" +#include "../../routing/include/event.hpp" +#include "../../routing/include/eventgroupinfo.hpp" +#include "../../routing/include/serviceinfo.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace sd { + +service_discovery_impl::service_discovery_impl( + service_discovery_host *_host, + const std::shared_ptr<configuration>& _configuration) + : io_(_host->get_io()), + host_(_host), + configuration_(_configuration), + port_(VSOMEIP_SD_DEFAULT_PORT), + reliable_(false), + serializer_(std::make_shared<serializer>( + configuration_->get_buffer_shrink_threshold())), + deserializer_(std::make_shared<deserializer>( + configuration_->get_buffer_shrink_threshold())), + ttl_timer_(_host->get_io()), + ttl_timer_runtime_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY / 2), + ttl_(VSOMEIP_SD_DEFAULT_TTL), + subscription_expiration_timer_(_host->get_io()), + max_message_size_(VSOMEIP_MAX_UDP_SD_PAYLOAD), + initial_delay_(0), + offer_debounce_time_(VSOMEIP_SD_DEFAULT_OFFER_DEBOUNCE_TIME), + repetitions_base_delay_(VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY), + repetitions_max_(VSOMEIP_SD_DEFAULT_REPETITIONS_MAX), + cyclic_offer_delay_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY), + offer_debounce_timer_(_host->get_io()), + find_debounce_time_(VSOMEIP_SD_DEFAULT_FIND_DEBOUNCE_TIME), + find_debounce_timer_(_host->get_io()), + main_phase_timer_(_host->get_io()), + is_suspended_(false), + is_diagnosis_(false), + last_msg_received_timer_(_host->get_io()), + last_msg_received_timer_timeout_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY + + (VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY / 10)) { + + next_subscription_expiration_ = std::chrono::steady_clock::now() + std::chrono::hours(24); +} + +service_discovery_impl::~service_discovery_impl() { +} + +boost::asio::io_context &service_discovery_impl::get_io() { + return io_; +} + +void +service_discovery_impl::init() { + runtime_ = std::dynamic_pointer_cast<sd::runtime>( + plugin_manager::get()->get_plugin( + plugin_type_e::SD_RUNTIME_PLUGIN, VSOMEIP_SD_LIBRARY)); + + unicast_ = configuration_->get_unicast_address(); + sd_multicast_ = configuration_->get_sd_multicast(); + boost::system::error_code ec; + sd_multicast_address_ = boost::asio::ip::address::from_string(sd_multicast_, ec); + + port_ = configuration_->get_sd_port(); + reliable_ = (configuration_->get_sd_protocol() == "tcp"); + max_message_size_ = (reliable_ ? VSOMEIP_MAX_TCP_SD_PAYLOAD : + VSOMEIP_MAX_UDP_SD_PAYLOAD); + + ttl_ = configuration_->get_sd_ttl(); + + // generate random initial delay based on initial delay min and max + std::uint32_t initial_delay_min = + configuration_->get_sd_initial_delay_min(); + std::uint32_t initial_delay_max = + configuration_->get_sd_initial_delay_max(); + if (initial_delay_min > initial_delay_max) { + const std::uint32_t tmp(initial_delay_min); + initial_delay_min = initial_delay_max; + initial_delay_max = tmp; + } + + try { + std::random_device r; + std::mt19937 e(r()); + std::uniform_int_distribution<std::uint32_t> distribution( + initial_delay_min, initial_delay_max); + initial_delay_ = std::chrono::milliseconds(distribution(e)); + } catch (const std::exception& e) { + VSOMEIP_ERROR << "Failed to generate random initial delay: " << e.what(); + + // Fallback to the Mersenne Twister engine + const auto seed = static_cast<std::mt19937::result_type>( + std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count()); + + std::mt19937 mtwister{seed}; + + // Interpolate between initial_delay bounds + initial_delay_ = std::chrono::milliseconds( + initial_delay_min + + (static_cast<std::int64_t>(mtwister()) * + static_cast<std::int64_t>(initial_delay_max - initial_delay_min) / + static_cast<std::int64_t>(std::mt19937::max() - + std::mt19937::min()))); + } + + + repetitions_base_delay_ = std::chrono::milliseconds( + configuration_->get_sd_repetitions_base_delay()); + repetitions_max_ = configuration_->get_sd_repetitions_max(); + cyclic_offer_delay_ = std::chrono::milliseconds( + configuration_->get_sd_cyclic_offer_delay()); + offer_debounce_time_ = std::chrono::milliseconds( + configuration_->get_sd_offer_debounce_time()); + ttl_timer_runtime_ = cyclic_offer_delay_ / 2; + find_debounce_time_ = std::chrono::milliseconds( + configuration_->get_sd_find_debounce_time()); + + ttl_factor_offers_ = configuration_->get_ttl_factor_offers(); + ttl_factor_subscriptions_ = configuration_->get_ttl_factor_subscribes(); + last_msg_received_timer_timeout_ = cyclic_offer_delay_ + + (cyclic_offer_delay_ / 10); +} + +void +service_discovery_impl::start() { + if (!endpoint_) { + endpoint_ = host_->create_service_discovery_endpoint( + sd_multicast_, port_, reliable_); + if (!endpoint_) { + VSOMEIP_ERROR << "Couldn't start service discovery"; + return; + } + } + { + std::lock_guard<std::mutex> its_lock(sessions_received_mutex_); + sessions_received_.clear(); + } + { + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + sessions_sent_.clear(); + } + + if (is_suspended_) { + // make sure to sent out FindService messages after resume + std::lock_guard<std::mutex> its_lock(requested_mutex_); + for (const auto &s : requested_) { + for (const auto &i : s.second) { + i.second->set_sent_counter(0); + } + } + + // rejoin multicast group + if (endpoint_ && !reliable_) { + auto its_server_endpoint + = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint_); + if (its_server_endpoint) + its_server_endpoint->join(sd_multicast_); + } + } + is_suspended_ = false; + start_main_phase_timer(); + start_offer_debounce_timer(true); + start_find_debounce_timer(true); + start_ttl_timer(); +} + +void +service_discovery_impl::stop() { + is_suspended_ = true; + stop_ttl_timer(); + stop_last_msg_received_timer(); + stop_main_phase_timer(); +} + +void +service_discovery_impl::request_service( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + ttl_t _ttl) { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + auto find_service = requested_.find(_service); + if (find_service != requested_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance == find_service->second.end()) { + find_service->second[_instance] + = std::make_shared<request>(_major, _minor, _ttl); + } + } else { + requested_[_service][_instance] + = std::make_shared<request>(_major, _minor, _ttl); + } +} + +void +service_discovery_impl::release_service( + service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + auto find_service = requested_.find(_service); + if (find_service != requested_.end()) { + find_service->second.erase(_instance); + } +} + +void +service_discovery_impl::update_request(service_t _service, instance_t _instance) { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + auto find_service = requested_.find(_service); + if (find_service != requested_.end()) { + auto find_instance = find_service->second.find(_instance); + if (find_instance != find_service->second.end()) { + find_instance->second->set_sent_counter( + std::uint8_t(repetitions_max_ + 1)); + } + } +} + +std::recursive_mutex& +service_discovery_impl::get_subscribed_mutex() { + return subscribed_mutex_; +} + +void +service_discovery_impl::subscribe( + service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + ttl_t _ttl, client_t _client, + const std::shared_ptr<eventgroupinfo> &_info) { + + if (is_suspended_) { + VSOMEIP_WARNING << "service_discovery::" << __func__ + << ": Ignoring subscription as we are suspended."; + return; + } + +#ifdef VSOMEIP_ENABLE_COMPAT + bool is_selective(_info ? _info->is_selective() : false); +#endif // VSOMEIP_ENABLE_COMPAT + + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto its_subscription = found_eventgroup->second; +#ifdef VSOMEIP_ENABLE_COMPAT + if (!its_subscription->is_selective() && is_selective) { + its_subscription->set_selective(true); + its_subscription->remove_client(VSOMEIP_ROUTING_CLIENT); + for (const auto &e : _info->get_events()) { + for (const auto &c : e->get_subscribers(_eventgroup)) { + its_subscription->add_client(c); + } + } + } +#endif // VSOMEIP_ENABLE_COMPAT + if (its_subscription->get_major() != _major) { + VSOMEIP_ERROR + << "Subscriptions to different versions of the same " + "service instance are not supported!"; + } else if (its_subscription->is_selective()) { + if (its_subscription->add_client(_client)) { + its_subscription->set_state(_client, + subscription_state_e::ST_NOT_ACKNOWLEDGED); + send_subscription(its_subscription, + _service, _instance, _eventgroup, + _client); + } + } + return; + } + } + } + + std::shared_ptr<endpoint> its_reliable, its_unreliable; + get_subscription_endpoints(_service, _instance, + its_reliable, its_unreliable); + + // New subscription + std::shared_ptr<subscription> its_subscription + = create_subscription( + _major, _ttl, its_reliable, its_unreliable, _info); + + if (!its_subscription) { + VSOMEIP_ERROR << __func__ + << ": creating subscription failed!"; + return; + } + + subscribed_[_service][_instance][_eventgroup] = its_subscription; + + its_subscription->add_client(_client); + its_subscription->set_state(_client, + subscription_state_e::ST_NOT_ACKNOWLEDGED); + + send_subscription(its_subscription, + _service, _instance, _eventgroup, + _client); +} + +void +service_discovery_impl::send_subscription( + const std::shared_ptr<subscription> &_subscription, + const service_t _service, const instance_t _instance, + const eventgroup_t _eventgroup, + const client_t _client) { + (void)_client; + + auto its_reliable = _subscription->get_endpoint(true); + auto its_unreliable = _subscription->get_endpoint(false); + + boost::asio::ip::address its_address; + get_subscription_address(its_reliable, its_unreliable, its_address); + if (!its_address.is_unspecified()) { + entry_data_t its_data; + const reliability_type_e its_reliability_type = + get_eventgroup_reliability(_service, _instance, _eventgroup, _subscription); + if (its_reliability_type == reliability_type_e::RT_UNRELIABLE && its_unreliable) { + if (its_unreliable->is_established()) { + its_data = create_eventgroup_entry(_service, _instance, + _eventgroup, _subscription, its_reliability_type); + } else { + _subscription->set_udp_connection_established(false); + } + } else if (its_reliability_type == reliability_type_e::RT_RELIABLE && its_reliable) { + if (its_reliable->is_established()) { + its_data = create_eventgroup_entry(_service, _instance, + _eventgroup, _subscription, its_reliability_type); + } else { + _subscription->set_tcp_connection_established(false); + } + } else if (its_reliability_type == reliability_type_e::RT_BOTH && + its_reliable && its_unreliable) { + if (its_reliable->is_established() && its_unreliable->is_established()) { + its_data = create_eventgroup_entry(_service, _instance, + _eventgroup, _subscription, its_reliability_type); + } else { + if (!its_reliable->is_established()) { + _subscription->set_tcp_connection_established(false); + } + if (!its_unreliable->is_established()) { + _subscription->set_udp_connection_established(false); + } + } + } else if (its_reliability_type == reliability_type_e::RT_UNKNOWN) { + VSOMEIP_WARNING << "sd::" << __func__ << ": couldn't determine reliability type for subscription to [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "] "; + } + + if (its_data.entry_) { + // TODO: Implement a simple path, that sends a single message + auto its_current_message = std::make_shared<message_impl>(); + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(its_current_message); + + add_entry_data(its_messages, its_data); + + serialize_and_send(its_messages, its_address); + } + } +} + +void +service_discovery_impl::get_subscription_endpoints( + service_t _service, instance_t _instance, + std::shared_ptr<endpoint> &_reliable, + std::shared_ptr<endpoint> &_unreliable) const { + _unreliable = host_->find_or_create_remote_client( + _service, _instance, false); + _reliable = host_->find_or_create_remote_client( + _service, _instance, true); +} + +void +service_discovery_impl::get_subscription_address( + const std::shared_ptr<endpoint> &_reliable, + const std::shared_ptr<endpoint> &_unreliable, + boost::asio::ip::address &_address) const { + if (_reliable) { + auto its_client_endpoint + = std::dynamic_pointer_cast<client_endpoint>(_reliable); + if (its_client_endpoint) { + its_client_endpoint->get_remote_address(_address); + return; + } + } + if (_unreliable) { + auto its_client_endpoint + = std::dynamic_pointer_cast<client_endpoint>(_unreliable); + if (its_client_endpoint) { + its_client_endpoint->get_remote_address(_address); + } + } +} + +void +service_discovery_impl::unsubscribe(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, client_t _client) { + std::shared_ptr < runtime > its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + auto its_current_message = std::make_shared<message_impl>(); + + boost::asio::ip::address its_address; + { + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto its_subscription = found_eventgroup->second; + if (its_subscription->remove_client(_client)) { + auto its_reliable = its_subscription->get_endpoint(true); + auto its_unreliable = its_subscription->get_endpoint(false); + get_subscription_address( + its_reliable, its_unreliable, its_address); + if (!its_subscription->has_client()) { + its_subscription->set_ttl(0); + } else if (its_subscription->is_selective()) { + // create a dummy subscription object to unsubscribe + // the single client. + auto its_major = its_subscription->get_major(); + + its_subscription = std::make_shared<subscription>(); + its_subscription->set_major(its_major); + its_subscription->set_ttl(0); + its_subscription->set_selective(true); + its_subscription->set_endpoint(its_reliable, true); + its_subscription->set_endpoint(its_unreliable, false); + } + } + + // For selective subscriptions, the client must be added again + // to generate the selective option + if (its_subscription->is_selective()) + its_subscription->add_client(_client); + + const reliability_type_e its_reliability_type = + get_eventgroup_reliability(_service, _instance, _eventgroup, its_subscription); + auto its_data = create_eventgroup_entry(_service, _instance, + _eventgroup, its_subscription, its_reliability_type); + if (its_data.entry_) + its_current_message->add_entry_data(its_data.entry_, its_data.options_); + + // Remove it again before updating (only impacts last unsubscribe) + if (its_subscription->is_selective()) + (void)its_subscription->remove_client(_client); + + // Ensure to update the "real" subscription + its_subscription = found_eventgroup->second; + + // Finally update the subscriptions + if (!its_subscription->has_client()) { + found_instance->second.erase(found_eventgroup); + if (found_instance->second.size() == 0) { + found_service->second.erase(found_instance); + } + } + } + } + } + } + + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(its_current_message); + + serialize_and_send(its_messages, its_address); +} + +void +service_discovery_impl::unsubscribe_all( + service_t _service, instance_t _instance) { + + auto its_current_message = std::make_shared<message_impl>(); + boost::asio::ip::address its_address; + + { + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + for (auto &its_eventgroup : found_instance->second) { + auto its_subscription = its_eventgroup.second; + its_subscription->set_ttl(0); + + const reliability_type_e its_reliability = + get_eventgroup_reliability(_service, _instance, + its_eventgroup.first, its_subscription); + + auto its_data = create_eventgroup_entry(_service, _instance, + its_eventgroup.first, its_subscription, its_reliability); + auto its_reliable = its_subscription->get_endpoint(true); + auto its_unreliable = its_subscription->get_endpoint(false); + get_subscription_address( + its_reliable, its_unreliable, its_address); + if (its_data.entry_) { + its_current_message->add_entry_data(its_data.entry_, its_data.options_); + } + } + found_instance->second.clear(); + } + } + } + + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(its_current_message); + + serialize_and_send(its_messages, its_address); +} + + +void +service_discovery_impl::unsubscribe_all_on_suspend() { + + std::map<boost::asio::ip::address, + std::vector<std::shared_ptr<message_impl> > > its_stopsubscribes; + + { + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + for (auto its_service : subscribed_) { + for (auto its_instance : its_service.second) { + for (auto &its_eventgroup : its_instance.second) { + boost::asio::ip::address its_address; + auto its_current_message = std::make_shared<message_impl>(); + auto its_subscription = its_eventgroup.second; + its_subscription->set_ttl(0); + const reliability_type_e its_reliability = + get_eventgroup_reliability(its_service.first, its_instance.first, + its_eventgroup.first, its_subscription); + auto its_data = create_eventgroup_entry(its_service.first, its_instance.first, + its_eventgroup.first, its_subscription, its_reliability); + auto its_reliable = its_subscription->get_endpoint(true); + auto its_unreliable = its_subscription->get_endpoint(false); + get_subscription_address( + its_reliable, its_unreliable, its_address); + if (its_data.entry_ + && its_current_message->add_entry_data(its_data.entry_, its_data.options_)) { + its_stopsubscribes[its_address].push_back(its_current_message); + } else { + VSOMEIP_WARNING << __func__ << ": Failed to create StopSubscribe entry for: " + << std::hex << std::setfill('0') + << std::setw(4) << its_service.first << "." + << std::setw(4) << its_instance.first << "." + << std::setw(4) << its_eventgroup.first + << " address: " << its_address.to_string(); + } + } + its_instance.second.clear(); + } + its_service.second.clear(); + } + subscribed_.clear(); + } + + for (auto its_address : its_stopsubscribes) { + if (!serialize_and_send(its_address.second, its_address.first)) { + VSOMEIP_WARNING << __func__ << ": Failed to send StopSubscribe to address: " + << its_address.first.to_string(); + } + } +} + +void +service_discovery_impl::remove_subscriptions( + service_t _service, instance_t _instance) { + + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + found_service->second.erase(_instance); + if (found_service->second.empty()) { + subscribed_.erase(found_service); + } + } +} + +std::pair<session_t, bool> +service_discovery_impl::get_session( + const boost::asio::ip::address &_address) { + std::pair<session_t, bool> its_session; + auto found_session = sessions_sent_.find(_address); + if (found_session == sessions_sent_.end()) { + its_session = sessions_sent_[_address] = { 1, true }; + } else { + its_session = found_session->second; + } + return its_session; +} + +void +service_discovery_impl::increment_session( + const boost::asio::ip::address &_address) { + auto found_session = sessions_sent_.find(_address); + if (found_session != sessions_sent_.end()) { + found_session->second.first++; + if (found_session->second.first == 0) { + found_session->second = { 1, false }; + } + } +} + +bool +service_discovery_impl::is_reboot( + const boost::asio::ip::address &_sender, + bool _is_multicast, + bool _reboot_flag, session_t _session) { + bool result(false); + + auto its_received = sessions_received_.find(_sender); + + // Initialize both sessions with 0. Thus, the session identifier + // for the session not being received from the network is stored + // as 0 and will never trigger the reboot detection. + session_t its_multicast_session(0), its_unicast_session(0); + + // Initialize both flags with true. Thus, the flag not being + // received from the network will never trigger the reboot detection. + bool its_multicast_reboot_flag(true), its_unicast_reboot_flag(true); + + if (_is_multicast) { + its_multicast_session = _session; + its_multicast_reboot_flag = _reboot_flag; + } else { + its_unicast_session = _session; + its_unicast_reboot_flag = _reboot_flag; + } + + if (its_received == sessions_received_.end()) { + sessions_received_[_sender] + = std::make_tuple(its_multicast_session, its_unicast_session, + its_multicast_reboot_flag, its_unicast_reboot_flag); + } else { + // Reboot detection: Either the flag has changed from false to true, + // or the session identifier overrun while the flag is true. + if (_reboot_flag + && ((_is_multicast && !std::get<2>(its_received->second)) + || (!_is_multicast && !std::get<3>(its_received->second)))) { + result = true; + } else { + session_t its_old_session; + bool its_old_reboot_flag; + + if (_is_multicast) { + its_old_session = std::get<0>(its_received->second); + its_old_reboot_flag = std::get<2>(its_received->second); + } else { + its_old_session = std::get<1>(its_received->second); + its_old_reboot_flag = std::get<3>(its_received->second); + } + + if (its_old_reboot_flag && _reboot_flag + && its_old_session >= _session) { + result = true; + } + } + + if (result == false) { + // no reboot -> update session/flag + if (_is_multicast) { + std::get<0>(its_received->second) = its_multicast_session; + std::get<2>(its_received->second) = its_multicast_reboot_flag; + } else { + std::get<1>(its_received->second) = its_unicast_session; + std::get<3>(its_received->second) = its_unicast_reboot_flag; + } + } else { + // reboot -> reset the sender data + sessions_received_.erase(_sender); + } + } + + return result; +} + +bool +service_discovery_impl::check_session_id_sequence(const boost::asio::ip::address &_sender, + const bool _is_multicast, const session_t &_session, + session_t &_missing_session) { + + using address_pair_t = std::pair<boost::asio::ip::address, bool>; + static std::map<address_pair_t, session_t> session_peer; + address_pair_t peer_to_peer(_sender, _is_multicast); + std::map<address_pair_t, session_t>::iterator it = session_peer.find(peer_to_peer); + if (it != session_peer.end()) { + if ((_session > it->second) && (_session != (it->second+1))) { + _missing_session = static_cast<session_t>(it->second+1); + session_peer[peer_to_peer] = _session; + return false; + } + } + + session_peer[peer_to_peer] = _session; + return true; +} + +void +service_discovery_impl::insert_find_entries( + std::vector<std::shared_ptr<message_impl> > &_messages, + const requests_t &_requests) { + + entry_data_t its_data; + its_data.entry_ = its_data.other_ = nullptr; + + for (const auto& its_service : _requests) { + for (const auto& its_instance : its_service.second) { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + auto its_request = its_instance.second; + + // check if release_service was called / offer was received + auto the_service = requested_.find(its_service.first); + if ( the_service != requested_.end() ) { + auto the_instance = the_service->second.find(its_instance.first); + if(the_instance != the_service->second.end() ) { + uint8_t its_sent_counter = its_request->get_sent_counter(); + if (its_sent_counter != repetitions_max_ + 1) { + auto its_entry = std::make_shared<serviceentry_impl>(); + if (its_entry) { + its_entry->set_type(entry_type_e::FIND_SERVICE); + its_entry->set_service(its_service.first); + its_entry->set_instance(its_instance.first); + its_entry->set_major_version(its_request->get_major()); + its_entry->set_minor_version(its_request->get_minor()); + its_entry->set_ttl(its_request->get_ttl()); + its_sent_counter++; + + its_request->set_sent_counter(its_sent_counter); + + its_data.entry_ = its_entry; + add_entry_data(_messages, its_data); + } else { + VSOMEIP_ERROR << "Failed to create service entry!"; + } + } + } + } + } + } +} + +void +service_discovery_impl::insert_offer_entries( + std::vector<std::shared_ptr<message_impl> > &_messages, + const services_t &_services, bool _ignore_phase) { + for (const auto& its_service : _services) { + for (const auto& its_instance : its_service.second) { + if ((!is_suspended_) + && ((!is_diagnosis_) + || (is_diagnosis_ + && !configuration_->is_someip(its_service.first, + its_instance.first)))) { + // Only insert services with configured endpoint(s) + if ((_ignore_phase || its_instance.second->is_in_mainphase()) + && (its_instance.second->get_endpoint(false) + || its_instance.second->get_endpoint(true))) { + insert_offer_service(_messages, its_instance.second); + } + } + } + } +} + +entry_data_t +service_discovery_impl::create_eventgroup_entry( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const std::shared_ptr<subscription> &_subscription, + reliability_type_e _reliability_type) { + + entry_data_t its_data; + its_data.entry_ = nullptr; + its_data.other_ = nullptr; + + std::shared_ptr<endpoint> its_reliable_endpoint(_subscription->get_endpoint(true)); + std::shared_ptr<endpoint> its_unreliable_endpoint(_subscription->get_endpoint(false)); + + bool insert_reliable(false); + bool insert_unreliable(false); + switch (_reliability_type) { + case reliability_type_e::RT_RELIABLE: + if (its_reliable_endpoint) { + insert_reliable = true; + } else { + VSOMEIP_WARNING << __func__ << ": Cannot create subscription as " + "reliable endpoint is zero: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + } + break; + case reliability_type_e::RT_UNRELIABLE: + if (its_unreliable_endpoint) { + insert_unreliable = true; + } else { + VSOMEIP_WARNING << __func__ << ": Cannot create subscription as " + "unreliable endpoint is zero: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + } + break; + case reliability_type_e::RT_BOTH: + if (its_reliable_endpoint && its_unreliable_endpoint) { + insert_reliable = true; + insert_unreliable = true; + } else { + VSOMEIP_WARNING << __func__ << ": Cannot create subscription as " + "endpoint is zero: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " reliable: " << !!its_reliable_endpoint + << " unreliable: " << !!its_unreliable_endpoint; + } + break; + default: + break; + } + + if (!insert_reliable && !insert_unreliable + && _reliability_type != reliability_type_e::RT_UNKNOWN) { + VSOMEIP_WARNING << __func__ << ": Didn't insert subscription as " + "subscription doesn't match reliability type: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "] " + << static_cast<uint16_t>(_reliability_type); + return its_data; + } + std::shared_ptr<eventgroupentry_impl> its_entry, its_other; + if (insert_reliable && its_reliable_endpoint) { + const std::uint16_t its_port = its_reliable_endpoint->get_local_port(); + if (its_port) { + its_entry = std::make_shared<eventgroupentry_impl>(); + if (!its_entry) { + VSOMEIP_ERROR << __func__ + << ": Could not create eventgroup entry."; + return its_data; + } + + its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_entry->set_service(_service); + its_entry->set_instance(_instance); + its_entry->set_eventgroup(_eventgroup); + its_entry->set_counter(0); + its_entry->set_major_version(_subscription->get_major()); + its_entry->set_ttl(_subscription->get_ttl()); + its_data.entry_ = its_entry; + + for (const auto its_client : _subscription->get_clients()) { + if (_subscription->get_state(its_client) + == subscription_state_e::ST_RESUBSCRIBING_NOT_ACKNOWLEDGED) { + its_other = std::make_shared<eventgroupentry_impl>(); + its_other->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_other->set_service(_service); + its_other->set_instance(_instance); + its_other->set_eventgroup(_eventgroup); + its_other->set_counter(0); + its_other->set_major_version(_subscription->get_major()); + its_other->set_ttl(0); + its_data.other_ = its_other; + break; + } + } + + auto its_option = create_ip_option(unicast_, its_port, true); + its_data.options_.push_back(its_option); + } else { + VSOMEIP_WARNING << __func__ << ": Cannot create subscription as " + "local reliable port is zero: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + its_data.entry_ = nullptr; + its_data.other_ = nullptr; + return its_data; + } + } + + if (insert_unreliable && its_unreliable_endpoint) { + const std::uint16_t its_port = its_unreliable_endpoint->get_local_port(); + if (its_port) { + if (!its_entry) { + its_entry = std::make_shared<eventgroupentry_impl>(); + if (!its_entry) { + VSOMEIP_ERROR << __func__ + << ": Could not create eventgroup entry."; + return its_data; + } + + its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_entry->set_service(_service); + its_entry->set_instance(_instance); + its_entry->set_eventgroup(_eventgroup); + its_entry->set_counter(0); + its_entry->set_major_version(_subscription->get_major()); + its_entry->set_ttl(_subscription->get_ttl()); + its_data.entry_ = its_entry; + } + + for (const auto its_client : _subscription->get_clients()) { + if (_subscription->get_state(its_client) + == subscription_state_e::ST_RESUBSCRIBING_NOT_ACKNOWLEDGED) { + if (!its_other) { + its_other = std::make_shared<eventgroupentry_impl>(); + its_other->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP); + its_other->set_service(_service); + its_other->set_instance(_instance); + its_other->set_eventgroup(_eventgroup); + its_other->set_counter(0); + its_other->set_major_version(_subscription->get_major()); + its_other->set_ttl(0); + its_data.other_ = its_other; + break; + } + } + } + + auto its_option = create_ip_option(unicast_, its_port, false); + its_data.options_.push_back(its_option); + } else { + VSOMEIP_WARNING << __func__ << ": Cannot create subscription as " + " local unreliable port is zero: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + its_data.entry_ = nullptr; + its_data.other_ = nullptr; + return its_data; + } + } + + if (its_entry &&_subscription->is_selective()) { + auto its_selective_option = std::make_shared<selective_option_impl>(); + its_selective_option->set_clients(_subscription->get_clients()); + its_data.options_.push_back(its_selective_option); + } + + if (its_entry && its_other) { + its_data.entry_ = its_other; + its_data.other_ = its_entry; + } + + return its_data; +} + +void +service_discovery_impl::insert_subscription_ack( + const std::shared_ptr<remote_subscription_ack>& _acknowledgement, + const std::shared_ptr<eventgroupinfo> &_info, ttl_t _ttl, + const std::shared_ptr<endpoint_definition> &_target, + const std::set<client_t> &_clients) { + std::unique_lock<std::recursive_mutex> its_lock(_acknowledgement->get_lock()); + auto its_message = _acknowledgement->get_current_message(); + + auto its_service = _info->get_service(); + auto its_instance = _info->get_instance(); + auto its_eventgroup = _info->get_eventgroup(); + auto its_major = _info->get_major(); + + for (const auto& its_entry : its_message->get_entries()) { + if (its_entry->is_eventgroup_entry()) { + std::shared_ptr<eventgroupentry_impl> its_eventgroup_entry + = std::dynamic_pointer_cast<eventgroupentry_impl>(its_entry); + if (its_eventgroup_entry->get_type() + == entry_type_e::SUBSCRIBE_EVENTGROUP_ACK + && its_eventgroup_entry->get_service() == its_service + && its_eventgroup_entry->get_instance() == its_instance + && its_eventgroup_entry->get_eventgroup() == its_eventgroup + && its_eventgroup_entry->get_major_version() == its_major + && its_eventgroup_entry->get_ttl() == _ttl) { + + if (_ttl > 0) { + if (_target) { + if (_target->is_reliable()) { + if (!its_eventgroup_entry->get_target(true)) { + its_eventgroup_entry->add_target(_target); + } + } else { + if (!its_eventgroup_entry->get_target(false)) { + its_eventgroup_entry->add_target(_target); + } + } + } + } + + if (_clients.size() > 1 || (*(_clients.begin())) != 0) { + auto its_selective_option = its_eventgroup_entry->get_selective_option(); + if (its_selective_option) + its_selective_option->set_clients(_clients); + } + + return; + } + } + } + + entry_data_t its_data; + + auto its_entry = std::make_shared<eventgroupentry_impl>(); + its_entry->set_type(entry_type_e::SUBSCRIBE_EVENTGROUP_ACK); + its_entry->set_service(its_service); + its_entry->set_instance(its_instance); + its_entry->set_eventgroup(its_eventgroup); + its_entry->set_major_version(its_major); + its_entry->set_reserved(0); + its_entry->set_counter(0); + // SWS_SD_00315 + its_entry->set_ttl(_ttl); + if (_ttl > 0) { + if (_target) { + its_entry->add_target(_target); + } + + boost::asio::ip::address its_address; + uint16_t its_port; + if (_info->get_multicast(its_address, its_port) + && _info->get_threshold() > 0) { + // SIP_SD_855 + // Only insert a multicast option for eventgroups with multicast threshold > 0 + auto its_option = create_ip_option(its_address, its_port, false); + its_data.options_.push_back(its_option); + } + } + + // Selective + if (_clients.size() > 1 || (*(_clients.begin())) != 0) { + auto its_selective_option = std::make_shared<selective_option_impl>(); + static_cast<void>(its_selective_option->set_clients(_clients)); + + its_data.options_.push_back(its_selective_option); + } + + its_data.entry_ = its_entry; + its_data.other_ = nullptr; + + add_entry_data_to_remote_subscription_ack_msg(_acknowledgement, its_data); +} + +bool +service_discovery_impl::send(bool _is_announcing) { + std::shared_ptr < runtime > its_runtime = runtime_.lock(); + if (its_runtime) { + std::vector<std::shared_ptr<message_impl> > its_messages; + std::shared_ptr<message_impl> its_message; + + if (_is_announcing) { + its_message = std::make_shared<message_impl>(); + its_messages.push_back(its_message); + + std::lock_guard<std::mutex> its_lock(offer_mutex_); + services_t its_offers = host_->get_offered_services(); + insert_offer_entries(its_messages, its_offers, false); + + // Serialize and send + return send(its_messages); + } + } + return false; +} + +// Interface endpoint_host +void +service_discovery_impl::on_message( + const byte_t *_data, length_t _length, + const boost::asio::ip::address &_sender, + bool _is_multicast) { +#if 0 + std::stringstream msg; + msg << "sdi::on_message: "; + for (length_t i = 0; i < _length; ++i) + msg << std::hex << std::setw(2) << std::setfill('0') << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::lock_guard<std::mutex> its_lock(check_ttl_mutex_); + std::lock_guard<std::mutex> its_session_lock(sessions_received_mutex_); + std::lock_guard<std::recursive_mutex> its_subscribed_lock(subscribed_mutex_); + + if(is_suspended_) { + return; + } + + // ignore all SD messages with source address equal to node's unicast address + if (!check_source_address(_sender)) { + return; + } + + if (_is_multicast) { + static bool must_start_last_msg_received_timer(true); + boost::system::error_code ec; + + std::lock_guard<std::mutex> its_lock_inner(last_msg_received_timer_mutex_); + if (0 < last_msg_received_timer_.cancel(ec) || must_start_last_msg_received_timer) { + must_start_last_msg_received_timer = false; + last_msg_received_timer_.expires_from_now( + last_msg_received_timer_timeout_, ec); + last_msg_received_timer_.async_wait( + std::bind(&service_discovery_impl::on_last_msg_received_timer_expired, + shared_from_this(), std::placeholders::_1)); + } + } + + current_remote_address_ = _sender; + std::shared_ptr<message_impl> its_message; + deserialize_data(_data, _length, its_message); + if (its_message) { + // ignore all messages which are sent with invalid header fields + if(!check_static_header_fields(its_message)) { + return; + } + + // Expire all subscriptions / services in case of reboot + if (is_reboot(_sender, _is_multicast, + its_message->get_reboot_flag(), its_message->get_session())) { + VSOMEIP_INFO << "Reboot detected: IP=" << _sender.to_string(); + remove_remote_offer_type_by_ip(_sender); + host_->expire_subscriptions(_sender); + host_->expire_services(_sender); + if (reboot_notification_handler_) { + ip_address_t ip; + if (_sender.is_v4()) { + ip.address_.v4_ = _sender.to_v4().to_bytes(); + ip.is_v4_ = true; + } else { + ip.address_.v6_ = _sender.to_v6().to_bytes(); + ip.is_v4_ = false; + } + reboot_notification_handler_(ip); + } + } + + session_t start_missing_sessions; + if (!check_session_id_sequence(_sender, _is_multicast, its_message->get_session(), start_missing_sessions)) { + std::stringstream log; + log << "SD messages lost from " << _sender.to_string() << " to "; + if (_is_multicast) { + log << sd_multicast_address_.to_string(); + } else { + log << unicast_.to_string(); + } + log << " - session_id[" << start_missing_sessions; + if (its_message->get_session() - start_missing_sessions != 1) { + log << ":" << its_message->get_session() -1; + } + log << "]"; + VSOMEIP_WARNING << log.str(); + } + + std::vector<std::shared_ptr<option_impl> > its_options + = its_message->get_options(); + + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + auto its_acknowledgement = std::make_shared<remote_subscription_ack>(_sender); + + std::vector<std::shared_ptr<message_impl> > its_resubscribes; + its_resubscribes.push_back(std::make_shared<message_impl>()); + + const message_impl::entries_t& its_entries = its_message->get_entries(); + const message_impl::entries_t::const_iterator its_end = its_entries.end(); + bool is_stop_subscribe_subscribe(false); + bool force_initial_events(false); + + bool sd_acceptance_queried(false); + expired_ports_t expired_ports; + sd_acceptance_state_t accept_state(expired_ports); + + for (auto iter = its_entries.begin(); iter != its_end; iter++) { + if (!sd_acceptance_queried) { + sd_acceptance_queried = true; + if (sd_acceptance_handler_) { + accept_state.sd_acceptance_required_ + = configuration_->is_protected_device(_sender); + remote_info_t remote; + remote.first_ = ANY_PORT; + remote.last_ = ANY_PORT; + remote.is_range_ = false; + if (_sender.is_v4()) { + remote.ip_.address_.v4_ = _sender.to_v4().to_bytes(); + remote.ip_.is_v4_ = true; + } else { + remote.ip_.address_.v6_ = _sender.to_v6().to_bytes(); + remote.ip_.is_v4_ = false; + } + accept_state.accept_entries_ = sd_acceptance_handler_(remote); + } else { + accept_state.accept_entries_ = true; + } + } + if ((*iter)->is_service_entry()) { + std::shared_ptr<serviceentry_impl> its_service_entry + = std::dynamic_pointer_cast<serviceentry_impl>(*iter); + bool its_unicast_flag = its_message->get_unicast_flag(); + process_serviceentry(its_service_entry, its_options, + its_unicast_flag, its_resubscribes, + _is_multicast, accept_state); + } else { + std::shared_ptr<eventgroupentry_impl> its_eventgroup_entry + = std::dynamic_pointer_cast<eventgroupentry_impl>(*iter); + + bool must_process(true); + // Do we need to process it? + if (its_eventgroup_entry->get_type() + == entry_type_e::SUBSCRIBE_EVENTGROUP) { + must_process = !has_same(iter, its_end, its_options); + } + + if (must_process) { + if (is_stop_subscribe_subscribe) { + force_initial_events = true; + } + is_stop_subscribe_subscribe = + check_stop_subscribe_subscribe(iter, its_end, its_options); + process_eventgroupentry(its_eventgroup_entry, its_options, + its_acknowledgement, _sender, _is_multicast, + is_stop_subscribe_subscribe, force_initial_events, + accept_state); + } + + } + } + + { + std::unique_lock<std::recursive_mutex> its_lock_inner(its_acknowledgement->get_lock()); + its_acknowledgement->complete(); + // TODO: Check the following logic... + if (its_acknowledgement->has_subscription()) { + update_acknowledgement(its_acknowledgement); + } else { + if (!its_acknowledgement->is_pending() + && !its_acknowledgement->is_done()) { + send_subscription_ack(its_acknowledgement); + } + } + } + + // check resubscriptions for validity + for (auto iter = its_resubscribes.begin(); iter != its_resubscribes.end();) { + if ((*iter)->get_entries().empty() || (*iter)->get_options().empty()) { + iter = its_resubscribes.erase(iter); + } else { + iter++; + } + } + if (!its_resubscribes.empty()) { + serialize_and_send(its_resubscribes, _sender); + } + } else { + VSOMEIP_ERROR << "service_discovery_impl::" << __func__ << ": Deserialization error."; + return; + } +} + +void service_discovery_impl::sent_messages(const byte_t* _data, length_t _size, + const boost::asio::ip::address& _remote_address) { + std::shared_ptr<message_impl> its_message; + deserialize_data(_data, _size, its_message); + if (its_message) { + const message_impl::entries_t& its_entries = its_message->get_entries(); + check_sent_offers(its_entries, _remote_address); + } +} + +// Entry processing +void service_discovery_impl::check_sent_offers(const message_impl::entries_t& _entries, + const boost::asio::ip::address& _remote_address) const { + + // only the offers messages sent by itself to multicast or unicast will be verified + // the another messages sent by itself will be ignored here + // the multicast offers are checked when SD receive its + // the unicast offers are checked in the send_cbk method, when SD send its + for (auto iter = _entries.begin(); iter != _entries.end(); iter++) { + if ((*iter)->get_type() == entry_type_e::OFFER_SERVICE && (*iter)->get_ttl() > 0) { + auto its_service = (*iter)->get_service(); + auto its_instance = (*iter)->get_instance(); + + std::shared_ptr<serviceinfo> its_info = + host_->get_offered_service(its_service, its_instance); + if (its_info) { + if (_remote_address.is_unspecified()) { + // enable proccess remote subscription for the services + // SD has already sent the offers for this service to multicast ip + its_info->set_accepting_remote_subscriptions(true); + } else { + if (!its_info->is_accepting_remote_subscriptions()) { + // enable to proccess remote subscription from remote ip for the services + its_info->add_remote_ip(_remote_address.to_string()); + } + } + } + } + } +} + +void service_discovery_impl::process_serviceentry( + std::shared_ptr<serviceentry_impl>& _entry, + const std::vector<std::shared_ptr<option_impl>>& _options, bool _unicast_flag, + std::vector<std::shared_ptr<message_impl>>& _resubscribes, bool _received_via_multicast, + const sd_acceptance_state_t& _sd_ac_state) { + + // Read service info from entry + entry_type_e its_type = _entry->get_type(); + service_t its_service = _entry->get_service(); + instance_t its_instance = _entry->get_instance(); + major_version_t its_major = _entry->get_major_version(); + minor_version_t its_minor = _entry->get_minor_version(); + ttl_t its_ttl = _entry->get_ttl(); + + // Read address info from options + boost::asio::ip::address its_reliable_address; + uint16_t its_reliable_port(ILLEGAL_PORT); + + boost::asio::ip::address its_unreliable_address; + uint16_t its_unreliable_port(ILLEGAL_PORT); + + for (auto i : { 1, 2 }) { + for (auto its_index : _entry->get_options(uint8_t(i))) { + if( _options.size() > its_index ) { + std::shared_ptr < option_impl > its_option = _options[its_index]; + + switch (its_option->get_type()) { + case option_type_e::IP4_ENDPOINT: { + std::shared_ptr < ipv4_option_impl > its_ipv4_option = + std::dynamic_pointer_cast < ipv4_option_impl + > (its_option); + + boost::asio::ip::address_v4 its_ipv4_address( + its_ipv4_option->get_address()); + + if (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + + + its_unreliable_address = its_ipv4_address; + its_unreliable_port = its_ipv4_option->get_port(); + } else { + its_reliable_address = its_ipv4_address; + its_reliable_port = its_ipv4_option->get_port(); + } + break; + } + case option_type_e::IP6_ENDPOINT: { + std::shared_ptr < ipv6_option_impl > its_ipv6_option = + std::dynamic_pointer_cast < ipv6_option_impl + > (its_option); + + boost::asio::ip::address_v6 its_ipv6_address( + its_ipv6_option->get_address()); + + if (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + its_unreliable_address = its_ipv6_address; + its_unreliable_port = its_ipv6_option->get_port(); + } else { + its_reliable_address = its_ipv6_address; + its_reliable_port = its_ipv6_option->get_port(); + } + break; + } + case option_type_e::IP4_MULTICAST: + case option_type_e::IP6_MULTICAST: + break; + case option_type_e::CONFIGURATION: + break; + case option_type_e::UNKNOWN: + default: + VSOMEIP_ERROR << __func__ << ": Unsupported service option"; + break; + } + } + } + } + + if (0 < its_ttl) { + switch (its_type) { + case entry_type_e::FIND_SERVICE: + process_findservice_serviceentry(its_service, its_instance, its_major, its_minor, + _unicast_flag); + break; + case entry_type_e::OFFER_SERVICE: + process_offerservice_serviceentry(its_service, its_instance, its_major, its_minor, + its_ttl, its_reliable_address, its_reliable_port, + its_unreliable_address, its_unreliable_port, + _resubscribes, _received_via_multicast, _sd_ac_state); + break; + case entry_type_e::UNKNOWN: + default: + VSOMEIP_ERROR << __func__ << ": Unsupported service entry type"; + } + } else if (its_type != entry_type_e::FIND_SERVICE + && (_sd_ac_state.sd_acceptance_required_ || _sd_ac_state.accept_entries_)) { + // stop sending find service in repetition phase + update_request(its_service, its_instance); + + remove_remote_offer_type(its_service, its_instance, + its_reliable_address, its_reliable_port, + its_unreliable_address, its_unreliable_port); + remove_subscriptions(its_service, its_instance); + if (!is_diagnosis_ && !is_suspended_) { + host_->del_routing_info(its_service, its_instance, + (its_reliable_port != ILLEGAL_PORT), + (its_unreliable_port != ILLEGAL_PORT)); + } + } +} + +void service_discovery_impl::process_offerservice_serviceentry( + service_t _service, instance_t _instance, major_version_t _major, minor_version_t _minor, + ttl_t _ttl, const boost::asio::ip::address& _reliable_address, uint16_t _reliable_port, + const boost::asio::ip::address& _unreliable_address, uint16_t _unreliable_port, + std::vector<std::shared_ptr<message_impl>>& _resubscribes, bool _received_via_multicast, + const sd_acceptance_state_t& _sd_ac_state) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) + return; + + bool is_secure = configuration_->is_secure_service(_service, _instance); + if (is_secure && + ((_reliable_port != ILLEGAL_PORT && + !configuration_->is_secure_port(_reliable_address, _reliable_port, true)) + || (_unreliable_port != ILLEGAL_PORT + && !configuration_->is_secure_port(_unreliable_address, _unreliable_port, false)))) { + + VSOMEIP_WARNING << __func__ << ": Ignoring offer of [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." << std::setw(4) << _instance + << "]"; + return; + } + + // stop sending find service in repetition phase + update_request(_service, _instance); + + const reliability_type_e offer_type = configuration_->get_reliability_type( + _reliable_address, _reliable_port, _unreliable_address,_unreliable_port); + + if (offer_type == reliability_type_e::RT_UNKNOWN) { + VSOMEIP_WARNING << __func__ << ": Unknown remote offer type [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "]"; + return; // Unknown remote offer type --> no way to access it! + } + + if (_sd_ac_state.sd_acceptance_required_) { + + auto expire_subscriptions_and_services = + [this, &_sd_ac_state](const boost::asio::ip::address& _address, + std::uint16_t _port, bool _reliable) { + const auto its_port_pair = std::make_pair(_reliable, _port); + if (_sd_ac_state.expired_ports_.find(its_port_pair) == + _sd_ac_state.expired_ports_.end()) { + VSOMEIP_WARNING << "service_discovery_impl::" << __func__ + << ": Do not accept offer from " + << _address.to_string() << ":" + << std::dec << _port << " reliable=" << _reliable; + remove_remote_offer_type_by_ip(_address, _port, _reliable); + host_->expire_subscriptions(_address, _port, _reliable); + host_->expire_services(_address, _port, _reliable); + _sd_ac_state.expired_ports_.insert(its_port_pair); + } + }; + + // return if the registered sd_acceptance handler returned false + // and for the provided port sd_acceptance is necessary + switch (offer_type) { + case reliability_type_e::RT_UNRELIABLE: + if (!_sd_ac_state.accept_entries_ + && configuration_->is_protected_port( + _unreliable_address, _unreliable_port, false)) { + expire_subscriptions_and_services(_unreliable_address, + _unreliable_port, false); + return; + } + break; + case reliability_type_e::RT_RELIABLE: + if (!_sd_ac_state.accept_entries_ + && configuration_->is_protected_port( + _reliable_address, _reliable_port, true)) { + expire_subscriptions_and_services(_reliable_address, + _reliable_port, true); + return; + } + break; + case reliability_type_e::RT_BOTH: + if (!_sd_ac_state.accept_entries_ + && (configuration_->is_protected_port( + _unreliable_address, _unreliable_port, false) + || configuration_->is_protected_port( + _reliable_address, _reliable_port, true))) { + expire_subscriptions_and_services(_unreliable_address, + _unreliable_port, false); + expire_subscriptions_and_services(_reliable_address, + _reliable_port, true); + return; + } + break; + case reliability_type_e::RT_UNKNOWN: + default: + break; + } + } + + if (update_remote_offer_type(_service, _instance, offer_type, _reliable_address, _reliable_port, + _unreliable_address, _unreliable_port, _received_via_multicast)) { + VSOMEIP_WARNING << __func__ << ": Remote offer type changed [" << std::hex << std::setw(4) + << std::setfill('0') << _service << "." << std::hex << std::setw(4) + << std::setfill('0') << _instance << "]"; + + // Only update eventgroup reliability type if it was initially unknown + auto its_eventgroups = host_->get_subscribed_eventgroups(_service, _instance); + for (auto eg : its_eventgroups) { + auto its_info = host_->find_eventgroup( + _service, _instance, eg); + if (its_info) { + if (its_info->is_reliability_auto_mode()) { + if (offer_type != reliability_type_e::RT_UNKNOWN + && offer_type != its_info->get_reliability()) { + VSOMEIP_WARNING << "sd::" << __func__ << ": eventgroup reliability type changed [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << eg << "]" + << " using reliability type: " + << std::setw(4) << static_cast<uint16_t>(offer_type); + its_info->set_reliability(offer_type); + } + } + } + } + } + + const bool was_previously_offered_by_unicast = set_offer_multicast_state( + _service, _instance, offer_type, _reliable_address, _reliable_port, _unreliable_address, + _unreliable_port, _received_via_multicast); + + // No need to resubscribe for unicast offers + if (_received_via_multicast) { + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (0 < found_instance->second.size()) { + for (const auto& its_eventgroup : found_instance->second) { + auto its_subscription = its_eventgroup.second; + std::shared_ptr<endpoint> its_reliable, its_unreliable; + get_subscription_endpoints(_service, _instance, its_reliable, + its_unreliable); + its_subscription->set_endpoint(its_reliable, true); + its_subscription->set_endpoint(its_unreliable, false); + for (const auto& its_client : its_subscription->get_clients()) { + if (its_subscription->get_state(its_client) + == subscription_state_e::ST_ACKNOWLEDGED) { + its_subscription->set_state(its_client, + subscription_state_e::ST_RESUBSCRIBING); + } else if (its_subscription->get_state(its_client) + != subscription_state_e::ST_ACKNOWLEDGED + && was_previously_offered_by_unicast) { + its_subscription->set_state(its_client, + subscription_state_e::ST_RESUBSCRIBING); + } else { + its_subscription->set_state( + its_client, + subscription_state_e::ST_RESUBSCRIBING_NOT_ACKNOWLEDGED); + } + } + const reliability_type_e its_reliability = get_eventgroup_reliability( + _service, _instance, its_eventgroup.first, its_subscription); + + auto its_data = + create_eventgroup_entry(_service, _instance, its_eventgroup.first, + its_subscription, its_reliability); + if (its_data.entry_) { + add_entry_data(_resubscribes, its_data); + } + for (const auto its_client : its_subscription->get_clients()) { + its_subscription->set_state(its_client, + subscription_state_e::ST_NOT_ACKNOWLEDGED); + } + } + } + } + } + } + + host_->add_routing_info(_service, _instance, _major, _minor, + _ttl * get_ttl_factor(_service, _instance, ttl_factor_offers_), + _reliable_address, _reliable_port, _unreliable_address, + _unreliable_port); +} + +void +service_discovery_impl::process_findservice_serviceentry( + service_t _service, instance_t _instance, + major_version_t _major, minor_version_t _minor, + bool _unicast_flag) { + + if (_instance != ANY_INSTANCE) { + std::shared_ptr<serviceinfo> its_info = host_->get_offered_service( + _service, _instance); + if (its_info) { + if (_major == ANY_MAJOR || _major == its_info->get_major()) { + if (_minor == 0xFFFFFFFF || _minor <= its_info->get_minor()) { + if (its_info->get_endpoint(false) || its_info->get_endpoint(true)) { + send_uni_or_multicast_offerservice(its_info, _unicast_flag); + } + } + } + } + } else { + std::map<instance_t, std::shared_ptr<serviceinfo>> offered_instances = + host_->get_offered_service_instances(_service); + // send back all available instances + for (const auto &found_instance : offered_instances) { + auto its_info = found_instance.second; + if (_major == ANY_MAJOR || _major == its_info->get_major()) { + if (_minor == 0xFFFFFFFF || _minor <= its_info->get_minor()) { + if (its_info->get_endpoint(false) || its_info->get_endpoint(true)) { + send_uni_or_multicast_offerservice(its_info, _unicast_flag); + } + } + } + } + } +} + +void +service_discovery_impl::send_unicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + auto its_offer_message(std::make_shared<message_impl>()); + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(its_offer_message); + + insert_offer_service(its_messages, _info); + + serialize_and_send(its_messages, current_remote_address_); +} + +void +service_discovery_impl::send_multicast_offer_service( + const std::shared_ptr<const serviceinfo> &_info) { + auto its_offer_message(std::make_shared<message_impl>()); + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(its_offer_message); + + insert_offer_service(its_messages, _info); + + serialize_and_send(its_messages, current_remote_address_); +} + +void +service_discovery_impl::on_endpoint_connected( + service_t _service, instance_t _instance, + const std::shared_ptr<endpoint> &_endpoint) { + std::shared_ptr<runtime> its_runtime = runtime_.lock(); + if (!its_runtime) { + return; + } + + // TODO: Simplify this method! It is not clear, why we need to check + // both endpoints here although the method is always called for a + // single one. + + std::vector<std::shared_ptr<message_impl> > its_messages; + its_messages.push_back(std::make_shared<message_impl>()); + boost::asio::ip::address its_address; + + std::shared_ptr<endpoint> its_dummy; + if (_endpoint->is_reliable()) + get_subscription_address(_endpoint, its_dummy, its_address); + else + get_subscription_address(its_dummy, _endpoint, its_address); + + { + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + if (0 < found_instance->second.size()) { + for (const auto &its_eventgroup : found_instance->second) { + std::shared_ptr<subscription> its_subscription(its_eventgroup.second); + if (its_subscription) { + if (!its_subscription->is_tcp_connection_established() || + !its_subscription->is_udp_connection_established()) { + const std::shared_ptr<const endpoint> its_reliable_endpoint( + its_subscription->get_endpoint(true)); + const std::shared_ptr<const endpoint> its_unreliable_endpoint( + its_subscription->get_endpoint(false)); + if (its_reliable_endpoint && its_reliable_endpoint->is_established()) { + if (its_reliable_endpoint.get() == _endpoint.get()) { + // mark tcp as established + its_subscription->set_tcp_connection_established(true); + } + } + if (its_unreliable_endpoint && its_unreliable_endpoint->is_established()) { + if (its_unreliable_endpoint.get() == _endpoint.get()) { + // mark udp as established + its_subscription->set_udp_connection_established(true); + } + } + + if ((its_reliable_endpoint && its_unreliable_endpoint && + its_subscription->is_tcp_connection_established() && + its_subscription->is_udp_connection_established()) || + (its_reliable_endpoint && !its_unreliable_endpoint && + its_subscription->is_tcp_connection_established()) || + (its_unreliable_endpoint && !its_reliable_endpoint && + its_subscription->is_udp_connection_established())) { + + std::shared_ptr<endpoint> its_unreliable; + std::shared_ptr<endpoint> its_reliable; + get_subscription_endpoints(_service, _instance, + its_reliable, its_unreliable); + get_subscription_address(its_reliable, its_unreliable, its_address); + + its_subscription->set_endpoint(its_reliable, true); + its_subscription->set_endpoint(its_unreliable, false); + for (const auto its_client : its_subscription->get_clients()) + its_subscription->set_state(its_client, + subscription_state_e::ST_NOT_ACKNOWLEDGED); + + const reliability_type_e its_reliability_type = + get_eventgroup_reliability(_service, _instance, its_eventgroup.first, its_subscription); + auto its_data = create_eventgroup_entry(_service, _instance, + its_eventgroup.first, its_subscription, its_reliability_type); + + if (its_data.entry_) { + add_entry_data(its_messages, its_data); + } + } + } + } + } + } + } + } + } + + serialize_and_send(its_messages, its_address); +} + +std::shared_ptr<option_impl> +service_discovery_impl::create_ip_option( + const boost::asio::ip::address &_address, uint16_t _port, + bool _is_reliable) const { + std::shared_ptr<option_impl> its_option; + if (_address.is_v4()) { + its_option = std::make_shared<ipv4_option_impl>( + _address, _port, _is_reliable); + } else { + its_option = std::make_shared<ipv6_option_impl>( + _address, _port, _is_reliable); + } + return its_option; +} + +void +service_discovery_impl::insert_offer_service( + std::vector<std::shared_ptr<message_impl> > &_messages, + const std::shared_ptr<const serviceinfo> &_info) { + entry_data_t its_data; + its_data.entry_ = its_data.other_ = nullptr; + + std::shared_ptr<endpoint> its_reliable = _info->get_endpoint(true); + if (its_reliable) { + auto its_new_option = create_ip_option(unicast_, + its_reliable->get_local_port(), true); + its_data.options_.push_back(its_new_option); + } + + std::shared_ptr<endpoint> its_unreliable = _info->get_endpoint(false); + if (its_unreliable) { + auto its_new_option = create_ip_option(unicast_, + its_unreliable->get_local_port(), false); + its_data.options_.push_back(its_new_option); + } + + auto its_entry = std::make_shared<serviceentry_impl>(); + if (its_entry) { + its_data.entry_ = its_entry; + + its_entry->set_type(entry_type_e::OFFER_SERVICE); + its_entry->set_service(_info->get_service()); + its_entry->set_instance(_info->get_instance()); + its_entry->set_major_version(_info->get_major()); + its_entry->set_minor_version(_info->get_minor()); + + ttl_t its_ttl = _info->get_ttl(); + if (its_ttl > 0) + its_ttl = ttl_; + its_entry->set_ttl(its_ttl); + + add_entry_data(_messages, its_data); + } else { + VSOMEIP_ERROR << __func__ << ": Failed to create service entry."; + } +} + +void +service_discovery_impl::process_eventgroupentry( + std::shared_ptr<eventgroupentry_impl> &_entry, + const std::vector<std::shared_ptr<option_impl> > &_options, + std::shared_ptr<remote_subscription_ack> &_acknowledgement, + const boost::asio::ip::address &_sender, + bool _is_multicast, + bool _is_stop_subscribe_subscribe, bool _force_initial_events, + const sd_acceptance_state_t& _sd_ac_state) { + + std::set<client_t> its_clients({0}); // maybe overridden for selectives + + auto its_sender = _acknowledgement->get_target_address(); + auto its_session = _entry->get_owning_message()->get_session(); + + service_t its_service = _entry->get_service(); + instance_t its_instance = _entry->get_instance(); + eventgroup_t its_eventgroup = _entry->get_eventgroup(); + entry_type_e its_type = _entry->get_type(); + major_version_t its_major = _entry->get_major_version(); + ttl_t its_ttl = _entry->get_ttl(); + + auto its_info = host_->find_eventgroup( + its_service, its_instance, its_eventgroup); + if (!its_info) { + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { + // We received a subscription for a non-existing eventgroup. + // --> Create dummy eventgroupinfo to send Nack. + its_info = std::make_shared<eventgroupinfo>(its_service, its_instance, + its_eventgroup, its_major, its_ttl, VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS); + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Received a SubscribeEventGroup entry for unknown eventgroup " + << " from: " << its_sender.to_string(ec) << " for: [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup + << "] session: " << std::setw(4) << its_session << ", ttl: " << its_ttl; + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + } else { + // We received a subscription [n]ack for an eventgroup that does not exist. + // --> Remove subscription. + unsubscribe(its_service, its_instance, its_eventgroup, VSOMEIP_ROUTING_CLIENT); + + boost::system::error_code ec; + VSOMEIP_WARNING << __func__ + << ": Received a SubscribeEventGroup[N]Ack entry for unknown eventgroup " + << " from: " << its_sender.to_string(ec) << " for: [" + << std::hex << std::setfill('0') + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(4) << its_eventgroup + << "] session: " << std::setw(4) << its_session << ", ttl: " << its_ttl; + } + return; + } + + if (_entry->get_owning_message()->get_return_code() != return_code) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ << ": Invalid return code in SOMEIP/SD header " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + + if (its_type == entry_type_e::SUBSCRIBE_EVENTGROUP) { + if (_is_multicast) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Received a SubscribeEventGroup entry on multicast address " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + if (_entry->get_num_options(1) == 0 + && _entry->get_num_options(2) == 0) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid number of options in SubscribeEventGroup entry " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + // increase number of required acks by one as number required acks + // is calculated based on the number of referenced options + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + if (_entry->get_owning_message()->get_options_length() < 12) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid options length in SOMEIP/SD message " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + if (_options.size() + // cast is needed in order to get unsigned type since int will be promoted + // by the + operator on 16 bit or higher machines. + < static_cast<std::vector<std::shared_ptr<option_impl>>::size_type>( + (_entry->get_num_options(1)) + (_entry->get_num_options(2)))) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << "Fewer options in SOMEIP/SD message than " + "referenced in EventGroup entry or malformed option received " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + // set to 0 to ensure an answer containing at least this subscribe_nack is sent out + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + if (_entry->get_owning_message()->get_someip_length() + < _entry->get_owning_message()->get_length() + && its_ttl > 0) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": SOME/IP length field in SubscribeEventGroup message header: [" + << std::dec << _entry->get_owning_message()->get_someip_length() + << "] bytes, is shorter than length of deserialized message: [" + << static_cast<uint32_t>(_entry->get_owning_message()->get_length()) << "] bytes. " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + } + + boost::asio::ip::address its_first_address; + uint16_t its_first_port(ILLEGAL_PORT); + bool is_first_reliable(false); + boost::asio::ip::address its_second_address; + uint16_t its_second_port(ILLEGAL_PORT); + bool is_second_reliable(false); + + for (auto i : { 1, 2 }) { + for (auto its_index : _entry->get_options(uint8_t(i))) { + std::shared_ptr < option_impl > its_option; + try { + its_option = _options.at(its_index); + } catch(const std::out_of_range&) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Fewer options in SD message than " + "referenced in EventGroup entry for " + "option run number: " + << i << " " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') + << its_session; + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type && its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + switch (its_option->get_type()) { + case option_type_e::IP4_ENDPOINT: { + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { + std::shared_ptr < ipv4_option_impl > its_ipv4_option = + std::dynamic_pointer_cast < ipv4_option_impl + > (its_option); + + boost::asio::ip::address_v4 its_ipv4_address( + its_ipv4_option->get_address()); + if (!check_layer_four_protocol(its_ipv4_option)) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + return; + } + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv4_address; + its_first_port = its_ipv4_option->get_port(); + is_first_reliable = (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + // reject subscription referencing two conflicting options of same protocol type + // ID: SIP_SD_1144 + if (is_first_reliable == is_second_reliable + && its_second_port != ILLEGAL_PORT) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Multiple IPv4 endpoint options of same kind referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session + << " is_first_reliable: " << is_first_reliable; + return; + } + + if (!check_ipv4_address(its_first_address) + || 0 == its_first_port) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid port or IP address in first IPv4 endpoint option specified! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv4_address; + its_second_port = its_ipv4_option->get_port(); + is_second_reliable = (its_ipv4_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + // reject subscription referencing two conflicting options of same protocol type + // ID: SIP_SD_1144 + if (is_second_reliable == is_first_reliable + && its_first_port != ILLEGAL_PORT) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Multiple IPv4 endpoint options of same kind referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session + << " is_second_reliable: " << is_second_reliable; + return; + } + + if (!check_ipv4_address(its_second_address) + || 0 == its_second_port) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid port or IP address in second IPv4 endpoint option specified! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + } else { + // TODO: error message, too many endpoint options! + } + } else { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid eventgroup option (IPv4 Endpoint)" + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + } + break; + } + case option_type_e::IP6_ENDPOINT: { + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { + std::shared_ptr < ipv6_option_impl > its_ipv6_option = + std::dynamic_pointer_cast < ipv6_option_impl + > (its_option); + + boost::asio::ip::address_v6 its_ipv6_address( + its_ipv6_option->get_address()); + if (!check_layer_four_protocol(its_ipv6_option)) { + if(its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << "Invalid layer 4 protocol type in IPv6 endpoint option specified! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv6_address; + its_first_port = its_ipv6_option->get_port(); + is_first_reliable = (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + if (is_first_reliable == is_second_reliable + && its_second_port != ILLEGAL_PORT) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Multiple IPv6 endpoint options of same kind referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session + << " is_first_reliable: " << is_first_reliable; + return; + } + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv6_address; + its_second_port = its_ipv6_option->get_port(); + is_second_reliable = (its_ipv6_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP); + + if (is_second_reliable == is_first_reliable + && its_first_port != ILLEGAL_PORT) { + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + } + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Multiple IPv6 endpoint options of same kind referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session + << " is_second_reliable: " << is_second_reliable; + return; + } + } else { + // TODO: error message, too many endpoint options! + } + } else { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid eventgroup option (IPv6 Endpoint) " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + } + break; + } + case option_type_e::IP4_MULTICAST: + if (entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { + std::shared_ptr < ipv4_option_impl > its_ipv4_option = + std::dynamic_pointer_cast < ipv4_option_impl + > (its_option); + + boost::asio::ip::address_v4 its_ipv4_address( + its_ipv4_option->get_address()); + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv4_address; + its_first_port = its_ipv4_option->get_port(); + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv4_address; + its_second_port = its_ipv4_option->get_port(); + } else { + // TODO: error message, too many endpoint options! + } + // ID: SIP_SD_946, ID: SIP_SD_1144 + if (its_first_port != ILLEGAL_PORT + && its_second_port != ILLEGAL_PORT) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Multiple IPv4 multicast options referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + } else { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid eventgroup option (IPv4 Multicast) " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + } + break; + case option_type_e::IP6_MULTICAST: + if (entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { + std::shared_ptr < ipv6_option_impl > its_ipv6_option = + std::dynamic_pointer_cast < ipv6_option_impl + > (its_option); + + boost::asio::ip::address_v6 its_ipv6_address( + its_ipv6_option->get_address()); + + if (its_first_port == ILLEGAL_PORT) { + its_first_address = its_ipv6_address; + its_first_port = its_ipv6_option->get_port(); + } else + if (its_second_port == ILLEGAL_PORT) { + its_second_address = its_ipv6_address; + its_second_port = its_ipv6_option->get_port(); + } else { + // TODO: error message, too many endpoint options! + } + // ID: SIP_SD_946, ID: SIP_SD_1144 + if (its_first_port != ILLEGAL_PORT + && its_second_port != ILLEGAL_PORT) { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << "Multiple IPv6 multicast options referenced! " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + return; + } + } else { + boost::system::error_code ec; + VSOMEIP_ERROR << __func__ + << ": Invalid eventgroup option (IPv6 Multicast) " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + } + break; + case option_type_e::CONFIGURATION: { + break; + } + case option_type_e::SELECTIVE: { + auto its_selective_option + = std::dynamic_pointer_cast<selective_option_impl>(its_option); + if (its_selective_option) { + its_clients = its_selective_option->get_clients(); + } + break; + } + case option_type_e::UNKNOWN: + default: + boost::system::error_code ec; + VSOMEIP_WARNING << __func__ + << ": Unsupported eventgroup option [" + << std::hex << static_cast<int>(its_option->get_type()) << "] " + << its_sender.to_string(ec) << " session: " + << std::hex << std::setw(4) << std::setfill('0') << its_session; + if (its_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, its_clients); + return; + } + break; + } + } + } + + if (entry_type_e::SUBSCRIBE_EVENTGROUP == its_type) { + handle_eventgroup_subscription( + its_service, its_instance, its_eventgroup, its_major, its_ttl, 0, 0, + its_first_address, its_first_port, is_first_reliable, its_second_address, + its_second_port, is_second_reliable, _acknowledgement, _is_stop_subscribe_subscribe, + _force_initial_events, its_clients, _sd_ac_state, its_info, _sender); + } else { + if (entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { //this type is used for ACK and NACK messages + if (its_ttl > 0) { + handle_eventgroup_subscription_ack(its_service, its_instance, + its_eventgroup, its_major, its_ttl, 0, + its_clients, _sender, + its_first_address, its_first_port); + } else { + handle_eventgroup_subscription_nack(its_service, its_instance, its_eventgroup, + 0, its_clients); + } + } + } +} + +void service_discovery_impl::handle_eventgroup_subscription( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, major_version_t _major, + ttl_t _ttl, uint8_t _counter, uint16_t _reserved, + const boost::asio::ip::address& _first_address, uint16_t _first_port, + bool _is_first_reliable, const boost::asio::ip::address& _second_address, + uint16_t _second_port, bool _is_second_reliable, + std::shared_ptr<remote_subscription_ack>& _acknowledgement, + bool _is_stop_subscribe_subscribe, bool _force_initial_events, + const std::set<client_t>& _clients, const sd_acceptance_state_t& _sd_ac_state, + const std::shared_ptr<eventgroupinfo>& _info, const boost::asio::ip::address& _sender) { + (void)_counter; + (void)_reserved; + + auto its_messages = _acknowledgement->get_messages(); + +#ifndef VSOMEIP_ENABLE_COMPAT + bool reliablility_nack(false); + if (_info) { + const bool first_port_set(_first_port != ILLEGAL_PORT); + const bool second_port_set(_second_port != ILLEGAL_PORT); + switch (_info->get_reliability()) { + case reliability_type_e::RT_UNRELIABLE: + if (!(first_port_set && !_is_first_reliable) + && !(second_port_set && !_is_second_reliable)) { + reliablility_nack = true; + } + break; + case reliability_type_e::RT_RELIABLE: + if (!(first_port_set && _is_first_reliable) + && !(second_port_set && _is_second_reliable)) { + reliablility_nack = true; + } + break; + case reliability_type_e::RT_BOTH: + if (_first_port == ILLEGAL_PORT || _second_port == ILLEGAL_PORT) { + reliablility_nack = true; + } + if (_is_first_reliable == _is_second_reliable) { + reliablility_nack = true; + } + break; + default: + break; + } + } + if (reliablility_nack && _ttl > 0) { + insert_subscription_ack(_acknowledgement, _info, 0, nullptr, _clients); + boost::system::error_code ec; + // TODO: Add sender and session id + VSOMEIP_WARNING << __func__ + << ": Subscription for [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " not valid: Event configuration (" + << static_cast<std::uint32_t>(_info->get_reliability()) + << ") does not match the provided endpoint options: " + << _first_address.to_string(ec) << ":" << std::dec << _first_port << " " + << _second_address.to_string(ec) << ":" << _second_port; + + return; + } + +#endif + + if (_ttl > 0) { + std::shared_ptr<serviceinfo> its_info = host_->get_offered_service(_service, _instance); + bool send_nack = false; + if (!its_info) { + send_nack = true; + } else { + if (!its_info->is_accepting_remote_subscriptions()) { // offer not sent to multicast ip + auto its_remote_ips = + its_info->get_remote_ip_accepting_sub(); // offer not sent to unicast + if (its_remote_ips.find(_sender.to_string()) == its_remote_ips.end()) + send_nack = true; + } + } + if (send_nack) { + insert_subscription_ack(_acknowledgement, _info, 0, nullptr, _clients); + return; + } + } + + std::shared_ptr<endpoint_definition> its_subscriber; + std::shared_ptr<endpoint_definition> its_reliable; + std::shared_ptr<endpoint_definition> its_unreliable; + + // wrong major version + if (_major != _info->get_major()) { + // Create a temporary info object with TTL=0 --> send NACK + auto its_info = std::make_shared<eventgroupinfo>(_service, _instance, + _eventgroup, _major, 0, VSOMEIP_DEFAULT_MAX_REMOTE_SUBSCRIBERS); + boost::system::error_code ec; + // TODO: Add session id + VSOMEIP_ERROR << __func__ + << ": Requested major version:[" << static_cast<uint32_t>(_major) + << "] in subscription to service: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " does not match with services major version:[" + << static_cast<uint32_t>(_info->get_major()) << "] subscriber: " + << _first_address.to_string(ec) << ":" << std::dec << _first_port; + if (_ttl > 0) { + insert_subscription_ack(_acknowledgement, its_info, 0, nullptr, _clients); + } + return; + } else { + boost::asio::ip::address its_first_address, its_second_address; + if (ILLEGAL_PORT != _first_port) { + uint16_t its_first_port(0); + its_subscriber = endpoint_definition::get( + _first_address, _first_port, _is_first_reliable, _service, _instance); + if (!_is_first_reliable && + _info->get_multicast(its_first_address, its_first_port) && + _info->is_sending_multicast()) { // udp multicast + its_unreliable = endpoint_definition::get( + its_first_address, its_first_port, false, _service, _instance); + } else if (_is_first_reliable) { // tcp unicast + its_reliable = its_subscriber; + // check if TCP connection is established by client + if (_ttl > 0 && !is_tcp_connected(_service, _instance, its_reliable)) { + insert_subscription_ack(_acknowledgement, _info, 0, nullptr, _clients); + // TODO: Add sender and session id + VSOMEIP_ERROR << "TCP connection to target1: [" + << its_reliable->get_address().to_string() + << ":" << its_reliable->get_port() + << "] not established for subscription to: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "] "; + return; + } + } else { // udp unicast + its_unreliable = its_subscriber; + } + } + + if (ILLEGAL_PORT != _second_port) { + uint16_t its_second_port(0); + its_subscriber = endpoint_definition::get( + _second_address, _second_port, _is_second_reliable, _service, _instance); + if (!_is_second_reliable && + _info->get_multicast(its_second_address, its_second_port) && + _info->is_sending_multicast()) { // udp multicast + its_unreliable = endpoint_definition::get( + its_second_address, its_second_port, false, _service, _instance); + } else if (_is_second_reliable) { // tcp unicast + its_reliable = its_subscriber; + // check if TCP connection is established by client + if (_ttl > 0 && !is_tcp_connected(_service, _instance, its_reliable)) { + insert_subscription_ack(_acknowledgement, _info, 0, nullptr, _clients); + // TODO: Add sender and session id + VSOMEIP_ERROR << "TCP connection to target2 : [" + << its_reliable->get_address().to_string() + << ":" << its_reliable->get_port() + << "] not established for subscription to: [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "] "; + return; + } + } else { // udp unicast + its_unreliable = its_subscriber; + } + } + } + + // check if the subscription should be rejected because of sd_acceptance_handling + if (_ttl > 0 && _sd_ac_state.sd_acceptance_required_) { + bool insert_nack(false); + if (_first_port != ILLEGAL_PORT && !_sd_ac_state.accept_entries_ + && configuration_->is_protected_port(_first_address, + _first_port, _is_first_reliable)) { + insert_nack = true; + } + if (!insert_nack && _second_port != ILLEGAL_PORT + && !_sd_ac_state.accept_entries_ + && configuration_->is_protected_port(_second_address, + _second_port, _is_second_reliable)) { + insert_nack = true; + } + if (insert_nack) { + insert_subscription_ack(_acknowledgement, _info, 0, nullptr, _clients); + return; + } + } + + if (its_subscriber) { + // Create subscription object + auto its_subscription = std::make_shared<remote_subscription>(); + its_subscription->set_eventgroupinfo(_info); + its_subscription->set_subscriber(its_subscriber); + its_subscription->set_reliable(its_reliable); + its_subscription->set_unreliable(its_unreliable); + its_subscription->reset(_clients); + + if (_ttl == 0) { // --> unsubscribe + its_subscription->set_ttl(0); + if (!_is_stop_subscribe_subscribe) { + { + std::lock_guard<std::mutex> its_lock(pending_remote_subscriptions_mutex_); + pending_remote_subscriptions_[its_subscription] = _acknowledgement; + _acknowledgement->add_subscription(its_subscription); + } + host_->on_remote_unsubscribe(its_subscription); + } + return; + } + + if (_force_initial_events) { + its_subscription->set_force_initial_events(true); + } + its_subscription->set_ttl(_ttl + * get_ttl_factor(_service, _instance, ttl_factor_subscriptions_)); + + { + std::lock_guard<std::mutex> its_lock(pending_remote_subscriptions_mutex_); + pending_remote_subscriptions_[its_subscription] = _acknowledgement; + _acknowledgement->add_subscription(its_subscription); + } + + host_->on_remote_subscribe(its_subscription, + std::bind(&service_discovery_impl::update_remote_subscription, + shared_from_this(), std::placeholders::_1)); + } +} + +void +service_discovery_impl::handle_eventgroup_subscription_nack( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + uint8_t _counter, const std::set<client_t> &_clients) { + (void)_counter; + + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + auto its_subscription = found_eventgroup->second; + for (const auto its_client : _clients) { + host_->on_subscribe_nack(its_client, + _service, _instance, _eventgroup, ANY_EVENT, + PENDING_SUBSCRIPTION_ID); // TODO: This is a dummy call... + } + + + if (!its_subscription->is_selective()) { + auto its_reliable = its_subscription->get_endpoint(true); + if (its_reliable) + its_reliable->restart(); + } + } + } + } +} + +void +service_discovery_impl::handle_eventgroup_subscription_ack( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + major_version_t _major, ttl_t _ttl, uint8_t _counter, + const std::set<client_t> &_clients, + const boost::asio::ip::address &_sender, + const boost::asio::ip::address &_address, uint16_t _port) { + (void)_major; + (void)_ttl; + (void)_counter; + + std::lock_guard<std::recursive_mutex> its_lock(subscribed_mutex_); + auto found_service = subscribed_.find(_service); + if (found_service != subscribed_.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + auto found_eventgroup = found_instance->second.find(_eventgroup); + if (found_eventgroup != found_instance->second.end()) { + for (const auto its_client : _clients) { + if (found_eventgroup->second->get_state(its_client) + == subscription_state_e::ST_NOT_ACKNOWLEDGED) { + found_eventgroup->second->set_state(its_client, + subscription_state_e::ST_ACKNOWLEDGED); + host_->on_subscribe_ack(its_client, + _service, _instance, _eventgroup, + ANY_EVENT, PENDING_SUBSCRIPTION_ID); + } + } + if (_address.is_multicast()) { + host_->on_subscribe_ack_with_multicast( + _service, _instance, _sender, _address, _port); + } + } + } + } +} + +bool service_discovery_impl::is_tcp_connected(service_t _service, + instance_t _instance, + const std::shared_ptr<endpoint_definition>& its_endpoint) { + bool is_connected = false; + std::shared_ptr<serviceinfo> its_info = host_->get_offered_service(_service, + _instance); + if (its_info) { + //get reliable server endpoint + auto its_reliable_server_endpoint = std::dynamic_pointer_cast< + tcp_server_endpoint_impl>(its_info->get_endpoint(true)); + if (its_reliable_server_endpoint + && its_reliable_server_endpoint->is_established_to(its_endpoint)) { + is_connected = true; + } + } + return is_connected; +} + +bool +service_discovery_impl::send( + const std::vector<std::shared_ptr<message_impl> > &_messages) { + + bool its_result(true); + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + for (const auto &m : _messages) { + if (m->has_entry()) { + std::pair<session_t, bool> its_session = get_session(unicast_); + m->set_session(its_session.first); + m->set_reboot_flag(its_session.second); + if (host_->send(VSOMEIP_SD_CLIENT, m, true)) { + increment_session(unicast_); + } + } else { + its_result = false; + } + } + return its_result; +} + +bool +service_discovery_impl::serialize_and_send( + const std::vector<std::shared_ptr<message_impl> > &_messages, + const boost::asio::ip::address &_address) { + bool its_result(true); + if (!_address.is_unspecified()) { + std::lock_guard<std::mutex> its_lock(serialize_mutex_); + for (const auto &m : _messages) { + if (m->has_entry()) { + std::pair<session_t, bool> its_session = get_session(_address); + m->set_session(its_session.first); + m->set_reboot_flag(its_session.second); + + if (serializer_->serialize(m.get())) { + if (host_->send_via_sd(endpoint_definition::get(_address, port_, + reliable_, m->get_service(), m->get_instance()), + serializer_->get_data(), serializer_->get_size(), + port_)) { + increment_session(_address); + } + } else { + VSOMEIP_ERROR << "service_discovery_impl::" << __func__ + << ": Serialization failed!"; + its_result = false; + } + serializer_->reset(); + } else { + its_result = false; + } + } + } + return its_result; +} + +void +service_discovery_impl::start_ttl_timer(int _shift) { + + std::lock_guard<std::mutex> its_lock(ttl_timer_mutex_); + + std::chrono::milliseconds its_timeout(ttl_timer_runtime_); + if (_shift > 0) { + if (its_timeout.count() > _shift) + its_timeout -= std::chrono::milliseconds(_shift); + + if (its_timeout.count() > VSOMEIP_MINIMUM_CHECK_TTL_TIMEOUT) + its_timeout = std::chrono::milliseconds(VSOMEIP_MINIMUM_CHECK_TTL_TIMEOUT); + } + + boost::system::error_code ec; + ttl_timer_.expires_from_now(its_timeout, ec); + ttl_timer_.async_wait( + std::bind(&service_discovery_impl::check_ttl, shared_from_this(), + std::placeholders::_1)); +} + +void +service_discovery_impl::stop_ttl_timer() { + std::lock_guard<std::mutex> its_lock(ttl_timer_mutex_); + boost::system::error_code ec; + ttl_timer_.cancel(ec); +} + +void +service_discovery_impl::check_ttl(const boost::system::error_code &_error) { + + static int its_counter(0); // count the times we were not able to call + // update_routing_info + if (!_error) { + { + std::unique_lock<std::mutex> its_lock(check_ttl_mutex_, std::try_to_lock); + if (its_lock.owns_lock()) { + its_counter = 0; + host_->update_routing_info(ttl_timer_runtime_); + } else { + its_counter++; + } + } + start_ttl_timer(its_counter * VSOMEIP_MINIMUM_CHECK_TTL_TIMEOUT); + } +} + +bool +service_discovery_impl::check_static_header_fields( + const std::shared_ptr<const message> &_message) const { + if(_message->get_protocol_version() != protocol_version) { + VSOMEIP_ERROR << "Invalid protocol version in SD header"; + return false; + } + if(_message->get_interface_version() != interface_version) { + VSOMEIP_ERROR << "Invalid interface version in SD header"; + return false; + } + if(_message->get_message_type() != message_type) { + VSOMEIP_ERROR << "Invalid message type in SD header"; + return false; + } + if(_message->get_return_code() > return_code_e::E_OK + && _message->get_return_code()< return_code_e::E_UNKNOWN) { + VSOMEIP_ERROR << "Invalid return code in SD header"; + return false; + } + return true; +} + +bool +service_discovery_impl::check_layer_four_protocol( + const std::shared_ptr<const ip_option_impl>& _ip_option) const { + if (_ip_option->get_layer_four_protocol() == layer_four_protocol_e::UNKNOWN) { + VSOMEIP_ERROR << "Invalid layer 4 protocol in IP endpoint option"; + return false; + } + return true; +} + +void +service_discovery_impl::start_subscription_expiration_timer() { + std::lock_guard<std::mutex> its_lock(subscription_expiration_timer_mutex_); + start_subscription_expiration_timer_unlocked(); +} + +void +service_discovery_impl::start_subscription_expiration_timer_unlocked() { + subscription_expiration_timer_.expires_at(next_subscription_expiration_); + subscription_expiration_timer_.async_wait( + std::bind(&service_discovery_impl::expire_subscriptions, + shared_from_this(), + std::placeholders::_1)); +} + +void +service_discovery_impl::stop_subscription_expiration_timer() { + std::lock_guard<std::mutex> its_lock(subscription_expiration_timer_mutex_); + stop_subscription_expiration_timer_unlocked(); +} + +void +service_discovery_impl::stop_subscription_expiration_timer_unlocked() { + subscription_expiration_timer_.cancel(); +} + +void +service_discovery_impl::expire_subscriptions( + const boost::system::error_code &_error) { + if (!_error) { + next_subscription_expiration_ = host_->expire_subscriptions(false); + start_subscription_expiration_timer(); + } +} + +bool +service_discovery_impl::check_ipv4_address( + const boost::asio::ip::address& its_address) const { + //Check unallowed ipv4 address + bool is_valid = true; + + static const boost::asio::ip::address_v4::bytes_type its_unicast_address = + unicast_.to_v4().to_bytes(); + const boost::asio::ip::address_v4::bytes_type endpoint_address = + its_address.to_v4().to_bytes(); + static const boost::asio::ip::address_v4::bytes_type its_netmask = + configuration_->get_netmask().to_v4().to_bytes(); + + //same address as unicast address of DUT not allowed + if (its_unicast_address == endpoint_address) { + VSOMEIP_ERROR << "Subscriber's IP address is same as host's address! : " + << its_address; + is_valid = false; + } else { + const std::uint32_t self = bithelper::read_uint32_be(&its_unicast_address[0]); + const std::uint32_t remote = bithelper::read_uint32_be(&endpoint_address[0]); + const std::uint32_t netmask = bithelper::read_uint32_be(&its_netmask[0]); + + if ((self & netmask) != (remote & netmask)) { + VSOMEIP_ERROR<< "Subscriber's IP isn't in the same subnet as host's IP: " + << its_address; + is_valid = false; + } + } + return is_valid; +} + +void +service_discovery_impl::offer_service(const std::shared_ptr<serviceinfo> &_info) { + service_t its_service = _info->get_service(); + service_t its_instance = _info->get_instance(); + + std::lock_guard<std::mutex> its_lock(collected_offers_mutex_); + // check if offer is in map + bool found(false); + const auto its_service_it = collected_offers_.find(its_service); + if (its_service_it != collected_offers_.end()) { + const auto its_instance_it = its_service_it->second.find(its_instance); + if (its_instance_it != its_service_it->second.end()) { + found = true; + } + } + if (!found) { + collected_offers_[its_service][its_instance] = _info; + } +} + +void +service_discovery_impl::start_offer_debounce_timer(bool _first_start) { + std::lock_guard<std::mutex> its_lock(offer_debounce_timer_mutex_); + boost::system::error_code ec; + if (_first_start) { + offer_debounce_timer_.expires_from_now(initial_delay_, ec); + } else { + offer_debounce_timer_.expires_from_now(offer_debounce_time_, ec); + } + if (ec) { + VSOMEIP_ERROR<< "service_discovery_impl::start_offer_debounce_timer " + "setting expiry time of timer failed: " << ec.message(); + } + offer_debounce_timer_.async_wait( + std::bind(&service_discovery_impl::on_offer_debounce_timer_expired, + this, std::placeholders::_1)); +} + +void +service_discovery_impl::start_find_debounce_timer(bool _first_start) { + std::lock_guard<std::mutex> its_lock(find_debounce_timer_mutex_); + boost::system::error_code ec; + if (_first_start) { + find_debounce_timer_.expires_from_now(initial_delay_, ec); + } else { + find_debounce_timer_.expires_from_now(find_debounce_time_, ec); + } + if (ec) { + VSOMEIP_ERROR<< "service_discovery_impl::start_find_debounce_timer " + "setting expiry time of timer failed: " << ec.message(); + } + find_debounce_timer_.async_wait( + std::bind( + &service_discovery_impl::on_find_debounce_timer_expired, + this, std::placeholders::_1)); +} + +// initial delay +void +service_discovery_impl::on_find_debounce_timer_expired( + const boost::system::error_code &_error) { + if(_error) { // timer was canceled + return; + } + // Only copy the accumulated requests of the initial wait phase + // if the sent counter for the request is zero. + requests_t repetition_phase_finds; + bool new_finds(false); + { + std::lock_guard<std::mutex> its_lock(requested_mutex_); + for (const auto& its_service : requested_) { + for (const auto& its_instance : its_service.second) { + if( its_instance.second->get_sent_counter() == 0) { + repetition_phase_finds[its_service.first][its_instance.first] = its_instance.second; + } + } + } + if (repetition_phase_finds.size()) { + new_finds = true; + } + } + + if (!new_finds) { + start_find_debounce_timer(false); + return; + } + + // Sent out finds for the first time as initial wait phase ended + std::vector<std::shared_ptr<message_impl>> its_messages; + auto its_message = std::make_shared<message_impl>(); + its_messages.push_back(its_message); + // Serialize and send FindService (increments sent counter in requested_ map) + insert_find_entries(its_messages, repetition_phase_finds); + send(its_messages); + + std::chrono::milliseconds its_delay(repetitions_base_delay_); + std::uint8_t its_repetitions(1); + + auto its_timer = std::make_shared<boost::asio::steady_timer>(host_->get_io()); + { + std::lock_guard<std::mutex> its_lock(find_repetition_phase_timers_mutex_); + find_repetition_phase_timers_[its_timer] = repetition_phase_finds; + } + + boost::system::error_code ec; + its_timer->expires_from_now(its_delay, ec); + if (ec) { + VSOMEIP_ERROR<< "service_discovery_impl::on_find_debounce_timer_expired " + "setting expiry time of timer failed: " << ec.message(); + } + its_timer->async_wait( + std::bind( + &service_discovery_impl::on_find_repetition_phase_timer_expired, + this, std::placeholders::_1, its_timer, its_repetitions, + its_delay.count())); + start_find_debounce_timer(false); +} + +void +service_discovery_impl::on_offer_debounce_timer_expired( + const boost::system::error_code &_error) { + if(_error) { // timer was canceled + return; + } + + // Copy the accumulated offers of the initial wait phase + services_t repetition_phase_offers; + bool new_offers(false); + { + std::vector<services_t::iterator> non_someip_services; + std::lock_guard<std::mutex> its_lock(collected_offers_mutex_); + if (collected_offers_.size()) { + if (is_diagnosis_) { + for (services_t::iterator its_service = collected_offers_.begin(); + its_service != collected_offers_.end(); its_service++) { + for (const auto& its_instance : its_service->second) { + if (!configuration_->is_someip( + its_service->first, its_instance.first)) { + non_someip_services.push_back(its_service); + } + } + } + for (auto its_service : non_someip_services) { + repetition_phase_offers.insert(*its_service); + collected_offers_.erase(its_service); + } + } else { + repetition_phase_offers = collected_offers_; + collected_offers_.clear(); + } + + new_offers = true; + } + } + + if (!new_offers) { + start_offer_debounce_timer(false); + return; + } + + // Sent out offers for the first time as initial wait phase ended + std::vector<std::shared_ptr<message_impl>> its_messages; + auto its_message = std::make_shared<message_impl>(); + its_messages.push_back(its_message); + insert_offer_entries(its_messages, repetition_phase_offers, true); + + // Serialize and send + send(its_messages); + + std::chrono::milliseconds its_delay(0); + std::uint8_t its_repetitions(0); + if (repetitions_max_) { + // Start timer for repetition phase the first time + // with 2^0 * repetitions_base_delay + its_delay = repetitions_base_delay_; + its_repetitions = 1; + } else { + // If repetitions_max is set to zero repetition phase is skipped, + // therefore wait one cyclic offer delay before entering main phase + its_delay = cyclic_offer_delay_; + its_repetitions = 0; + } + + auto its_timer = std::make_shared<boost::asio::steady_timer>(host_->get_io()); + + { + std::lock_guard<std::mutex> its_lock(repetition_phase_timers_mutex_); + repetition_phase_timers_[its_timer] = repetition_phase_offers; + } + + boost::system::error_code ec; + its_timer->expires_from_now(its_delay, ec); + if (ec) { + VSOMEIP_ERROR<< "service_discovery_impl::on_offer_debounce_timer_expired " + "setting expiry time of timer failed: " << ec.message(); + } + its_timer->async_wait( + std::bind( + &service_discovery_impl::on_repetition_phase_timer_expired, + this, std::placeholders::_1, its_timer, its_repetitions, + its_delay.count())); + start_offer_debounce_timer(false); +} + +void +service_discovery_impl::on_repetition_phase_timer_expired( + const boost::system::error_code &_error, + const std::shared_ptr<boost::asio::steady_timer>& _timer, + std::uint8_t _repetition, std::uint32_t _last_delay) { + if (_error) { + return; + } + if (_repetition == 0) { + std::lock_guard<std::mutex> its_lock(repetition_phase_timers_mutex_); + // We waited one cyclic offer delay, the offers can now be sent in the + // main phase and the timer can be deleted + move_offers_into_main_phase(_timer); + } else { + std::lock_guard<std::mutex> its_lock(repetition_phase_timers_mutex_); + auto its_timer_pair = repetition_phase_timers_.find(_timer); + if (its_timer_pair != repetition_phase_timers_.end()) { + std::chrono::milliseconds new_delay(0); + std::uint8_t repetition(0); + bool move_to_main(false); + if (_repetition <= repetitions_max_) { + // Sent offers, double time to wait and start timer again. + + new_delay = std::chrono::milliseconds(_last_delay * 2); + repetition = ++_repetition; + } else { + // Repetition phase is now over we have to sleep one cyclic + // offer delay before it's allowed to sent the offer again. + // If the last offer was sent shorter than half the + // configured cyclic_offer_delay_ago the offers are directly + // moved into the mainphase to avoid potentially sleeping twice + // the cyclic offer delay before moving the offers in to main + // phase + if (last_offer_shorter_half_offer_delay_ago()) { + move_to_main = true; + } else { + new_delay = cyclic_offer_delay_; + repetition = 0; + } + } + std::vector<std::shared_ptr<message_impl>> its_messages; + auto its_message = std::make_shared<message_impl>(); + its_messages.push_back(its_message); + insert_offer_entries(its_messages, its_timer_pair->second, true); + + // Serialize and send + send(its_messages); + if (move_to_main) { + move_offers_into_main_phase(_timer); + return; + } + boost::system::error_code ec; + its_timer_pair->first->expires_from_now(new_delay, ec); + if (ec) { + VSOMEIP_ERROR << + "service_discovery_impl::on_repetition_phase_timer_expired " + "setting expiry time of timer failed: " << ec.message(); + } + its_timer_pair->first->async_wait( + std::bind( + &service_discovery_impl::on_repetition_phase_timer_expired, + this, std::placeholders::_1, its_timer_pair->first, + repetition, new_delay.count())); + } + } +} + +void +service_discovery_impl::on_find_repetition_phase_timer_expired( + const boost::system::error_code &_error, + const std::shared_ptr<boost::asio::steady_timer>& _timer, + std::uint8_t _repetition, std::uint32_t _last_delay) { + if (_error) { + return; + } + + std::lock_guard<std::mutex> its_lock(find_repetition_phase_timers_mutex_); + auto its_timer_pair = find_repetition_phase_timers_.find(_timer); + if (its_timer_pair != find_repetition_phase_timers_.end()) { + std::chrono::milliseconds new_delay(0); + std::uint8_t repetition(0); + if (_repetition <= repetitions_max_) { + // Sent findService entries in one message, double time to wait and start timer again. + std::vector<std::shared_ptr<message_impl>> its_messages; + auto its_message = std::make_shared<message_impl>(); + its_messages.push_back(its_message); + insert_find_entries(its_messages, its_timer_pair->second); + send(its_messages); + new_delay = std::chrono::milliseconds(_last_delay * 2); + repetition = ++_repetition; + } else { + // Repetition phase is now over, erase the timer on next expiry time + find_repetition_phase_timers_.erase(its_timer_pair); + return; + } + boost::system::error_code ec; + its_timer_pair->first->expires_from_now(new_delay, ec); + if (ec) { + VSOMEIP_ERROR << __func__ + << "setting expiry time of timer failed: " << ec.message(); + } + its_timer_pair->first->async_wait( + std::bind( + &service_discovery_impl::on_find_repetition_phase_timer_expired, + this, std::placeholders::_1, its_timer_pair->first, + repetition, new_delay.count())); + } +} + +void +service_discovery_impl::move_offers_into_main_phase( + const std::shared_ptr<boost::asio::steady_timer> &_timer) { + // HINT: make sure to lock the repetition_phase_timers_mutex_ before calling + // this function set flag on all serviceinfos bound to this timer that they + // will be included in the cyclic offers from now on + const auto its_timer = repetition_phase_timers_.find(_timer); + if (its_timer != repetition_phase_timers_.end()) { + for (const auto& its_service : its_timer->second) { + for (const auto& its_instance : its_service.second) { + its_instance.second->set_is_in_mainphase(true); + } + } + repetition_phase_timers_.erase(_timer); + } +} + +bool +service_discovery_impl::stop_offer_service( + const std::shared_ptr<serviceinfo> &_info, bool _send) { + std::lock_guard<std::mutex> its_lock(offer_mutex_); + _info->set_ttl(0); + // disable accepting remote subscriptions + _info->set_accepting_remote_subscriptions(false); + const service_t its_service = _info->get_service(); + const instance_t its_instance = _info->get_instance(); + bool stop_offer_required(false); + // Delete from initial phase offers + { + std::lock_guard<std::mutex> its_lock_inner(collected_offers_mutex_); + if (collected_offers_.size()) { + auto its_service_it = collected_offers_.find(its_service); + if (its_service_it != collected_offers_.end()) { + auto its_instance_it = its_service_it->second.find(its_instance); + if (its_instance_it != its_service_it->second.end()) { + if (its_instance_it->second == _info) { + its_service_it->second.erase(its_instance_it); + + if (!collected_offers_[its_service].size()) { + collected_offers_.erase(its_service_it); + } + } + } + } + } + // No need to sent out a stop offer message here as all services + // instances contained in the collected offers weren't broadcasted yet + } + + // Delete from repetition phase offers + { + std::lock_guard<std::mutex> its_lock_inner(repetition_phase_timers_mutex_); + for (auto rpt = repetition_phase_timers_.begin(); + rpt != repetition_phase_timers_.end();) { + auto its_service_it = rpt->second.find(its_service); + if (its_service_it != rpt->second.end()) { + auto its_instance_it = its_service_it->second.find(its_instance); + if (its_instance_it != its_service_it->second.end()) { + if (its_instance_it->second == _info) { + its_service_it->second.erase(its_instance_it); + stop_offer_required = true; + if (!rpt->second[its_service].size()) { + rpt->second.erase(its_service); + } + } + } + } + if (!rpt->second.size()) { + rpt = repetition_phase_timers_.erase(rpt); + } else { + ++rpt; + } + } + } + + if (!_send) { + // stop offer required + return (_info->is_in_mainphase() || stop_offer_required); + } else if(_info->is_in_mainphase() || stop_offer_required) { + // Send stop offer + return send_stop_offer(_info); + } + return false; + // sent out NACKs for all pending subscriptions + // TODO: remote_subscription_not_acknowledge_all(its_service, its_instance); +} + +bool +service_discovery_impl::send_stop_offer(const std::shared_ptr<serviceinfo> &_info) { + + if (_info->get_endpoint(false) || _info->get_endpoint(true)) { + std::vector<std::shared_ptr<message_impl> > its_messages; + auto its_current_message = std::make_shared<message_impl>(); + its_messages.push_back(its_current_message); + + insert_offer_service(its_messages, _info); + + // Serialize and send + return send(its_messages); + } + return false; +} + +bool +service_discovery_impl::send_collected_stop_offers(const std::vector<std::shared_ptr<serviceinfo>> &_infos) { + + std::vector<std::shared_ptr<message_impl> > its_messages; + auto its_current_message = std::make_shared<message_impl>(); + its_messages.push_back(its_current_message); + + // pack multiple stop offers together + for (auto its_info : _infos) { + if (its_info->get_endpoint(false) || its_info->get_endpoint(true)) { + insert_offer_service(its_messages, its_info); + } + } + + // Serialize and send + return send(its_messages); +} + +void +service_discovery_impl::start_main_phase_timer() { + std::lock_guard<std::mutex> its_lock(main_phase_timer_mutex_); + boost::system::error_code ec; + main_phase_timer_.expires_from_now(cyclic_offer_delay_, ec); + if (ec) { + VSOMEIP_ERROR<< "service_discovery_impl::start_main_phase_timer " + "setting expiry time of timer failed: " << ec.message(); + } + main_phase_timer_.async_wait( + std::bind(&service_discovery_impl::on_main_phase_timer_expired, + this, std::placeholders::_1)); +} + +void +service_discovery_impl::stop_main_phase_timer() { + std::scoped_lock<std::mutex> its_lock(main_phase_timer_mutex_); + boost::system::error_code ec; + main_phase_timer_.cancel(ec); +} + +void +service_discovery_impl::on_main_phase_timer_expired( + const boost::system::error_code &_error) { + if (_error) { + return; + } + send(true); + start_main_phase_timer(); +} + +void +service_discovery_impl::send_uni_or_multicast_offerservice( + const std::shared_ptr<const serviceinfo> &_info, bool _unicast_flag) { + if (_unicast_flag) { // SID_SD_826 + if (last_offer_shorter_half_offer_delay_ago()) { // SIP_SD_89 + send_unicast_offer_service(_info); + } else { // SIP_SD_90 + send_multicast_offer_service(_info); + } + } else { // SID_SD_826 + send_unicast_offer_service(_info); + } +} + +bool +service_discovery_impl::last_offer_shorter_half_offer_delay_ago() { + // Get remaining time to next offer since last offer + std::chrono::milliseconds remaining(0); + { + std::lock_guard<std::mutex> its_lock(main_phase_timer_mutex_); + remaining = std::chrono::duration_cast<std::chrono::milliseconds>( + main_phase_timer_.expires_from_now()); + } + if (std::chrono::milliseconds(0) > remaining) { + remaining = cyclic_offer_delay_; + } + const std::chrono::milliseconds half_cyclic_offer_delay = + cyclic_offer_delay_ / 2; + + return remaining > half_cyclic_offer_delay; +} + +bool +service_discovery_impl::check_source_address( + const boost::asio::ip::address &its_source_address) const { + + bool is_valid = true; + // Check if source address is same as nodes unicast address + if (unicast_ == its_source_address) { + VSOMEIP_ERROR << "Source address of message is same as DUT's unicast address! : " + << its_source_address.to_string(); + is_valid = false; + } + return is_valid; +} + +void +service_discovery_impl::set_diagnosis_mode(const bool _activate) { + + is_diagnosis_ = _activate; +} + +bool +service_discovery_impl::get_diagnosis_mode() { + + return is_diagnosis_; +} + +void +service_discovery_impl::update_remote_subscription( + const std::shared_ptr<remote_subscription> &_subscription) { + + if (!_subscription->is_pending() || 0 == _subscription->get_answers()) { + std::shared_ptr<remote_subscription_ack> its_ack; + { + std::lock_guard<std::mutex> its_lock(pending_remote_subscriptions_mutex_); + auto found_ack = pending_remote_subscriptions_.find(_subscription); + if (found_ack != pending_remote_subscriptions_.end()) { + its_ack = found_ack->second; + } + } + if (its_ack) { + std::unique_lock<std::recursive_mutex> its_lock(its_ack->get_lock()); + update_acknowledgement(its_ack); + } + } +} + +void +service_discovery_impl::update_acknowledgement( + const std::shared_ptr<remote_subscription_ack> &_acknowledgement) { + + if (_acknowledgement->is_complete() + && !_acknowledgement->is_pending() + && !_acknowledgement->is_done()) { + + send_subscription_ack(_acknowledgement); + + std::lock_guard<std::mutex> its_lock(pending_remote_subscriptions_mutex_); + for (const auto &its_subscription : _acknowledgement->get_subscriptions()) + pending_remote_subscriptions_.erase(its_subscription); + } +} + +void +service_discovery_impl::update_subscription_expiration_timer( + const std::vector<std::shared_ptr<message_impl> > &_messages) { + std::lock_guard<std::mutex> its_lock(subscription_expiration_timer_mutex_); + const std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + stop_subscription_expiration_timer_unlocked(); + for (const auto &m : _messages) { + for (const auto &e : m->get_entries()) { + if (e && e->get_type() == entry_type_e::SUBSCRIBE_EVENTGROUP_ACK + && e->get_ttl()) { + const std::chrono::steady_clock::time_point its_expiration = now + + std::chrono::seconds(e->get_ttl() + * get_ttl_factor( + e->get_service(), e->get_instance(), + ttl_factor_subscriptions_)); + if (its_expiration < next_subscription_expiration_) { + next_subscription_expiration_ = its_expiration; + } + } + } + } + start_subscription_expiration_timer_unlocked(); +} + +bool +service_discovery_impl::check_stop_subscribe_subscribe( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t& _options) const { + + return (*_iter)->get_ttl() == 0 + && (*_iter)->get_type() == entry_type_e::STOP_SUBSCRIBE_EVENTGROUP + && has_opposite(_iter, _end, _options); +} + +bool +service_discovery_impl::has_opposite( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t &_options) const { + const auto its_entry = std::dynamic_pointer_cast<eventgroupentry_impl>(*_iter); + auto its_other = std::next(_iter); + for (; its_other != _end; its_other++) { + if ((*its_other)->get_type() == entry_type_e::SUBSCRIBE_EVENTGROUP) { + const auto its_other_entry + = std::dynamic_pointer_cast<eventgroupentry_impl>(*its_other); + if ((its_entry->get_ttl() == 0 && its_other_entry->get_ttl() > 0) + || (its_entry->get_ttl() > 0 && its_other_entry->get_ttl() == 0)) { + if (its_entry->matches(*(its_other_entry.get()), _options)) + return true; + } + } + } + return false; +} + +bool +service_discovery_impl::has_same( + message_impl::entries_t::const_iterator _iter, + message_impl::entries_t::const_iterator _end, + const message_impl::options_t &_options) const { + const auto its_entry = std::dynamic_pointer_cast<eventgroupentry_impl>(*_iter); + auto its_other = std::next(_iter); + for (; its_other != _end; its_other++) { + if (its_entry->get_type() == (*its_other)->get_type()) { + const auto its_other_entry + = std::dynamic_pointer_cast<eventgroupentry_impl>(*its_other); + if (its_entry->get_ttl() == its_other_entry->get_ttl() + && its_entry->matches(*(its_other_entry.get()), _options)) { + return true; + } + } + } + return false; +} + +bool +service_discovery_impl::is_subscribed( + const std::shared_ptr<eventgroupentry_impl> &_entry, + const message_impl::options_t &_options) const { + const auto its_service = _entry->get_service(); + const auto its_instance = _entry->get_instance(); + auto its_info = host_->find_eventgroup( + its_service, its_instance, _entry->get_eventgroup()); + if (its_info) { + std::shared_ptr<endpoint_definition> its_reliable, its_unreliable; + for (const auto& o : _options) { + if (o->get_type() == option_type_e::IP4_ENDPOINT) { + const auto its_endpoint_option + = std::dynamic_pointer_cast<ipv4_option_impl>(o); + if (its_endpoint_option) { + if (its_endpoint_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP) { + its_reliable = endpoint_definition::get( + boost::asio::ip::address_v4( + its_endpoint_option->get_address()), + its_endpoint_option->get_port(), + true, + its_service, its_instance); + } else if (its_endpoint_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + its_unreliable = endpoint_definition::get( + boost::asio::ip::address_v4( + its_endpoint_option->get_address()), + its_endpoint_option->get_port(), + false, + its_service, its_instance); + } + } + } else if (o->get_type() == option_type_e::IP6_ENDPOINT) { + const auto its_endpoint_option + = std::dynamic_pointer_cast<ipv6_option_impl>(o); + if (its_endpoint_option->get_layer_four_protocol() + == layer_four_protocol_e::TCP) { + its_reliable = endpoint_definition::get( + boost::asio::ip::address_v6( + its_endpoint_option->get_address()), + its_endpoint_option->get_port(), + true, + its_service, its_instance); + } else if (its_endpoint_option->get_layer_four_protocol() + == layer_four_protocol_e::UDP) { + its_unreliable = endpoint_definition::get( + boost::asio::ip::address_v6( + its_endpoint_option->get_address()), + its_endpoint_option->get_port(), + false, + its_service, its_instance); + } + } + } + if (its_reliable || its_unreliable) { + for (const auto& its_subscription : its_info->get_remote_subscriptions()) { + if ((!its_reliable || its_subscription->get_reliable() == its_reliable) + && (!its_unreliable || its_subscription->get_unreliable() == its_unreliable)) { + return true; + } + } + } + } + return false; +} + +configuration::ttl_factor_t +service_discovery_impl::get_ttl_factor( + service_t _service, instance_t _instance, + const configuration::ttl_map_t& _ttl_map) const { + configuration::ttl_factor_t its_ttl_factor(1); + auto found_service = _ttl_map.find(_service); + if (found_service != _ttl_map.end()) { + auto found_instance = found_service->second.find(_instance); + if (found_instance != found_service->second.end()) { + its_ttl_factor = found_instance->second; + } + } + return its_ttl_factor; +} + +void +service_discovery_impl::on_last_msg_received_timer_expired( + const boost::system::error_code &_error) { + + if (!_error) { + // We didn't receive a multicast message within 110% of the cyclic_offer_delay_ + VSOMEIP_WARNING << "Didn't receive a multicast SD message for " << + std::dec << last_msg_received_timer_timeout_.count() << "ms."; + + // Rejoin multicast group + if (endpoint_ && !reliable_) { + auto its_server_endpoint + = std::dynamic_pointer_cast<udp_server_endpoint_impl>(endpoint_); + if (its_server_endpoint) { + its_server_endpoint->leave(sd_multicast_); + its_server_endpoint->join(sd_multicast_); + } + } + { + boost::system::error_code ec; + std::lock_guard<std::mutex> its_lock(last_msg_received_timer_mutex_); + last_msg_received_timer_.expires_from_now(last_msg_received_timer_timeout_, ec); + last_msg_received_timer_.async_wait( + std::bind( + &service_discovery_impl::on_last_msg_received_timer_expired, + shared_from_this(), std::placeholders::_1)); + } + } +} + +void +service_discovery_impl::stop_last_msg_received_timer() { + std::lock_guard<std::mutex> its_lock(last_msg_received_timer_mutex_); + boost::system::error_code ec; + last_msg_received_timer_.cancel(ec); +} + +reliability_type_e +service_discovery_impl::get_remote_offer_type( + service_t _service, instance_t _instance) const { + std::lock_guard<std::mutex> its_lock(remote_offer_types_mutex_); + auto found_si = remote_offer_types_.find(std::make_pair(_service, _instance)); + if (found_si != remote_offer_types_.end()) { + return found_si->second; + } + return reliability_type_e::RT_UNKNOWN; +} + +reliability_type_e +service_discovery_impl::get_remote_offer_type( + const std::shared_ptr<subscription> &_subscription) const { + bool has_reliable = (_subscription->get_endpoint(true) != nullptr); + bool has_unreliable = (_subscription->get_endpoint(false) != nullptr); + + return (has_reliable ? + (has_unreliable ? + reliability_type_e::RT_BOTH : + reliability_type_e::RT_RELIABLE) : + (has_unreliable ? + reliability_type_e::RT_UNRELIABLE : + reliability_type_e::RT_UNKNOWN)); +} + + +bool service_discovery_impl::update_remote_offer_type( + service_t _service, instance_t _instance, reliability_type_e _offer_type, + const boost::asio::ip::address& _reliable_address, std::uint16_t _reliable_port, + const boost::asio::ip::address& _unreliable_address, std::uint16_t _unreliable_port, + bool _received_via_multicast) { + bool ret(false); + std::lock_guard<std::mutex> its_lock(remote_offer_types_mutex_); + const remote_offer_info_t its_service_instance(_service, _instance, _received_via_multicast); + auto found_si = remote_offer_types_.find(its_service_instance.service_info); + if (found_si != remote_offer_types_.end()) { + if (found_si->second != _offer_type ) { + found_si->second = _offer_type; + ret = true; + } + } else { + remote_offer_types_[its_service_instance.service_info] = _offer_type; + } + switch (_offer_type) { + case reliability_type_e::RT_UNRELIABLE: + remote_offers_by_ip_[_unreliable_address][std::make_pair(false, _unreliable_port)].insert( + its_service_instance); + break; + case reliability_type_e::RT_RELIABLE: + remote_offers_by_ip_[_reliable_address][std::make_pair(true, _reliable_port)].insert( + its_service_instance); + break; + case reliability_type_e::RT_BOTH: + remote_offers_by_ip_[_unreliable_address][std::make_pair(false, _unreliable_port)].insert( + its_service_instance); + remote_offers_by_ip_[_unreliable_address][std::make_pair(true, _reliable_port)].insert( + its_service_instance); + break; + case reliability_type_e::RT_UNKNOWN: + default: + VSOMEIP_WARNING << __func__ << ": unknown offer type [" << std::hex << std::setw(4) + << std::setfill('0') << _service << "." << std::hex << std::setw(4) + << std::setfill('0') << _instance << "]" << static_cast<int>(_offer_type); + break; + } + return ret; +} + +void +service_discovery_impl::remove_remote_offer_type( + service_t _service, instance_t _instance, + const boost::asio::ip::address &_reliable_address, + std::uint16_t _reliable_port, + const boost::asio::ip::address &_unreliable_address, + std::uint16_t _unreliable_port) { + std::lock_guard<std::mutex> its_lock(remote_offer_types_mutex_); + const remote_offer_info_t its_service_instance(_service, _instance); + + remote_offer_types_.erase(its_service_instance.service_info); + + auto delete_from_remote_offers_by_ip = [&](const boost::asio::ip::address& _address, + std::uint16_t _port, bool _reliable) { + const auto found_address = remote_offers_by_ip_.find(_address); + if (found_address != remote_offers_by_ip_.end()) { + auto found_port = found_address->second.find(std::make_pair(_reliable, _port)); + if (found_port != found_address->second.end()) { + if (found_port->second.erase(its_service_instance)) { + if (found_port->second.empty()) { + found_address->second.erase(found_port); + if (found_address->second.empty()) { + remote_offers_by_ip_.erase(found_address); + } + } + } + } + } + }; + if (_reliable_port != ILLEGAL_PORT) { + delete_from_remote_offers_by_ip(_reliable_address, _reliable_port, + true); + } + if (_unreliable_port != ILLEGAL_PORT) { + delete_from_remote_offers_by_ip(_unreliable_address, _unreliable_port, + false); + } +} + +void service_discovery_impl::remove_remote_offer_type_by_ip( + const boost::asio::ip::address &_address) { + remove_remote_offer_type_by_ip(_address, ANY_PORT, false); +} + +void service_discovery_impl::remove_remote_offer_type_by_ip( + const boost::asio::ip::address &_address, std::uint16_t _port, bool _reliable) { + std::lock_guard<std::mutex> its_lock(remote_offer_types_mutex_); + const auto found_address = remote_offers_by_ip_.find(_address); + if (found_address != remote_offers_by_ip_.end()) { + if (_port == ANY_PORT) { + for (const auto& port : found_address->second) { + for (const auto& si : port.second) { + remote_offer_types_.erase(si.service_info); + } + } + remote_offers_by_ip_.erase(_address); + } else { + const auto its_port_reliability = std::make_pair(_reliable, _port); + const auto found_port = found_address->second.find(its_port_reliability); + if (found_port != found_address->second.end()) { + for (const auto& si : found_port->second) { + remote_offer_types_.erase(si.service_info); + } + found_address->second.erase(found_port); + if (found_address->second.empty()) { + remote_offers_by_ip_.erase(found_address); + } + } + } + } +} + +bool service_discovery_impl::set_offer_multicast_state( + service_t _service, instance_t _instance, reliability_type_e _offer_type, + const boost::asio::ip::address& _reliable_address, port_t _reliable_port, + const boost::asio::ip::address& _unreliable_address, std::uint16_t _unreliable_port, + bool _received_via_multicast) { + + bool was_unicast = false; + + auto check_offer_info = [this, &was_unicast, _received_via_multicast]( + const boost::asio::ip::address& address, bool reliable, + port_t port, service_t service_id, instance_t instance_id) { + auto found_address = remote_offers_by_ip_.find(address); + if (found_address != remote_offers_by_ip_.end()) { + auto found_port = found_address->second.find(std::make_pair(reliable, port)); + if (found_port != found_address->second.end()) { + auto found_offer_info = found_port->second.find({service_id, instance_id}); + if (found_offer_info != found_port->second.end()) { + if (!found_offer_info->offer_received_via_multicast) { + was_unicast = true; + found_offer_info->offer_received_via_multicast = _received_via_multicast; + } + } + } + } + }; + + switch (_offer_type) { + case reliability_type_e::RT_UNRELIABLE: + check_offer_info(_unreliable_address, false, _unreliable_port, _service, _instance); + break; + case reliability_type_e::RT_RELIABLE: + check_offer_info(_reliable_address, true, _reliable_port, _service, _instance); + break; + case reliability_type_e::RT_BOTH: + check_offer_info(_unreliable_address, false, _unreliable_port, _service, _instance); + check_offer_info(_reliable_address, true, _reliable_port, _service, _instance); + break; + case reliability_type_e::RT_UNKNOWN: + default: + VSOMEIP_WARNING << __func__ << ": unknown offer type [" << std::hex << std::setw(4) + << std::setfill('0') << _service << "." << std::hex << std::setw(4) + << std::setfill('0') << _instance << "]" << static_cast<int>(_offer_type); + break; + } + + return was_unicast; +} + +std::shared_ptr<subscription> +service_discovery_impl::create_subscription(major_version_t _major, ttl_t _ttl, + const std::shared_ptr<endpoint>& _reliable, + const std::shared_ptr<endpoint>& _unreliable, + const std::shared_ptr<eventgroupinfo>& _info) const { + auto its_subscription = std::make_shared<subscription>(); + its_subscription->set_major(_major); + its_subscription->set_ttl(_ttl); + + if (_reliable) { + its_subscription->set_endpoint(_reliable, true); + its_subscription->set_tcp_connection_established(_reliable->is_established()); + } + + if (_unreliable) { + its_subscription->set_endpoint(_unreliable, false); + its_subscription->set_udp_connection_established(_unreliable->is_established()); + } + + // check whether the eventgroup is selective + its_subscription->set_selective(_info->is_selective()); + + its_subscription->set_eventgroupinfo(_info); + + return its_subscription; +} + +void +service_discovery_impl::send_subscription_ack( + const std::shared_ptr<remote_subscription_ack> &_acknowledgement) { + + if (_acknowledgement->is_done()) + return; + + _acknowledgement->done(); + + std::uint32_t its_max_answers(1); // Must be 1 as "_acknowledgement" not + // necessarily contains subscriptions + bool do_not_answer(false); + std::shared_ptr<remote_subscription> its_parent; + + // Find highest number of necessary answers + for (const auto& its_subscription : _acknowledgement->get_subscriptions()) { + auto its_answers = its_subscription->get_answers(); + if (its_answers > its_max_answers) { + its_max_answers = its_answers; + } else if (its_answers == 0) { + do_not_answer = true; + its_parent = its_subscription->get_parent(); + } + } + + if (do_not_answer) { + if (its_parent) { + std::lock_guard<std::mutex> its_lock(pending_remote_subscriptions_mutex_); + auto its_parent_ack = pending_remote_subscriptions_[its_parent]; + if (its_parent_ack) { + for (const auto &its_subscription : its_parent_ack->get_subscriptions()) { + if (its_subscription != its_parent) + its_subscription->set_answers(its_subscription->get_answers() + 1); + } + } + } + return; + } + + // send messages + for (std::uint32_t i = 0; i < its_max_answers; i++) { + for (const auto &its_subscription : _acknowledgement->get_subscriptions()) { + if (i < its_subscription->get_answers()) { + if (its_subscription->get_ttl() > 0) { + auto its_info = its_subscription->get_eventgroupinfo(); + if (its_info) { + std::set<client_t> its_acked; + std::set<client_t> its_nacked; + for (const auto& its_client : its_subscription->get_clients()) { + if (its_subscription->get_client_state(its_client) + == remote_subscription_state_e::SUBSCRIPTION_ACKED) { + its_acked.insert(its_client); + } else { + its_nacked.insert(its_client); + } + } + + if (0 < its_acked.size()) { + insert_subscription_ack(_acknowledgement, its_info, + its_subscription->get_ttl(), + its_subscription->get_subscriber(), its_acked); + } + + if (0 < its_nacked.size()) { + insert_subscription_ack(_acknowledgement, its_info, + 0, + its_subscription->get_subscriber(), its_nacked); + } + } + } + } + } + + auto its_messages = _acknowledgement->get_messages(); + serialize_and_send(its_messages, _acknowledgement->get_target_address()); + update_subscription_expiration_timer(its_messages); + } + + std::this_thread::yield(); + + // We might need to send initial events + for (const auto &its_subscription : _acknowledgement->get_subscriptions()) { + // Assumption: We do _NOT_ need to check whether this is a child + // subscription, as this only applies to selective events, which + // are owned by exclusive event groups. + if (its_subscription->get_ttl() > 0 + && its_subscription->is_initial()) { + its_subscription->set_initial(false); + auto its_info = its_subscription->get_eventgroupinfo(); + if (its_info) { + its_info->send_initial_events( + its_subscription->get_reliable(), + its_subscription->get_unreliable()); + } + } + } +} + +void +service_discovery_impl::add_entry_data( + std::vector<std::shared_ptr<message_impl> > &_messages, + const entry_data_t &_data) { + auto its_current_message = _messages.back(); + const auto is_fitting = its_current_message->add_entry_data( + _data.entry_, _data.options_, _data.other_); + if (!is_fitting) { + its_current_message = std::make_shared<message_impl>(); + (void)its_current_message->add_entry_data( + _data.entry_, _data.options_, _data.other_); + _messages.push_back(its_current_message); + } +} + +void +service_discovery_impl::add_entry_data_to_remote_subscription_ack_msg( + const std::shared_ptr<remote_subscription_ack>& _acknowledgement, + const entry_data_t &_data) { + auto its_current_message = _acknowledgement->get_current_message(); + const auto is_fitting = its_current_message->add_entry_data( + _data.entry_, _data.options_, _data.other_); + if (!is_fitting) { + its_current_message = _acknowledgement->add_message(); + (void)its_current_message->add_entry_data( + _data.entry_, _data.options_, _data.other_); + } +} + +void +service_discovery_impl::register_sd_acceptance_handler( + const sd_acceptance_handler_t &_handler) { + sd_acceptance_handler_ = _handler; +} + +void +service_discovery_impl::register_reboot_notification_handler( + const reboot_notification_handler_t &_handler) { + reboot_notification_handler_ = _handler; +} + +reliability_type_e service_discovery_impl::get_eventgroup_reliability( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const std::shared_ptr<subscription>& _subscription) { + reliability_type_e its_reliability = reliability_type_e::RT_UNKNOWN; + auto its_info = _subscription->get_eventgroupinfo().lock(); + if (its_info) { + its_reliability = its_info->get_reliability(); + if (its_reliability == reliability_type_e::RT_UNKNOWN + && its_info->is_reliability_auto_mode()) { + // fallback: determine how service is offered + // and update reliability type of eventgroup + its_reliability = get_remote_offer_type(_service, _instance); + VSOMEIP_WARNING << "sd::" << __func__ << ": couldn't determine eventgroup reliability type for [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]" + << " using reliability type: " + << std::setw(4) << static_cast<uint16_t>(its_reliability); + its_info->set_reliability(its_reliability); + } + } else { + VSOMEIP_WARNING << "sd::" << __func__ << ": couldn't lock eventgroupinfo [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "] "; + auto its_eg_info = host_->find_eventgroup(_service, _instance, _eventgroup); + if (its_eg_info) { + _subscription->set_eventgroupinfo(its_eg_info); + its_reliability = its_eg_info->get_reliability(); + } + } + + if (its_reliability == reliability_type_e::RT_UNKNOWN) { + VSOMEIP_WARNING << "sd::" << __func__ << ": eventgroup reliability type is unknown [" + << std::hex << std::setfill('0') + << std::setw(4) << _service << "." + << std::setw(4) << _instance << "." + << std::setw(4) << _eventgroup << "]"; + } + return its_reliability; +} + +void service_discovery_impl::deserialize_data(const byte_t* _data, const length_t& _size, + std::shared_ptr<message_impl>& _message) { + std::lock_guard its_lock(deserialize_mutex_); + deserializer_->set_data(_data, _size); + _message = std::shared_ptr<message_impl>(deserializer_->deserialize_sd_message()); + deserializer_->reset(); +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/serviceentry_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/serviceentry_impl.cpp new file mode 100644 index 00000000000..f3fc70da0c1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/serviceentry_impl.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/serviceentry_impl.hpp" +#include "../../message/include/deserializer.hpp" +#include "../../message/include/serializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +serviceentry_impl::serviceentry_impl() { + minor_version_ = 0; +} + +serviceentry_impl::~serviceentry_impl() { +} + +minor_version_t serviceentry_impl::get_minor_version() const { + return minor_version_; +} + +void serviceentry_impl::set_minor_version(minor_version_t _version) { + minor_version_ = _version; +} + +bool serviceentry_impl::serialize(vsomeip_v3::serializer *_to) const { + bool is_successful = entry_impl::serialize(_to); + + is_successful = is_successful + && _to->serialize(static_cast<uint8_t>(major_version_)); + is_successful = is_successful + && _to->serialize(static_cast<uint32_t>(ttl_), true); + is_successful = is_successful + && _to->serialize(static_cast<uint32_t>(minor_version_)); + + return is_successful; +} + +bool serviceentry_impl::deserialize(vsomeip_v3::deserializer *_from) { + bool is_successful = entry_impl::deserialize(_from); + + uint8_t tmp_major_version(0); + is_successful = is_successful && _from->deserialize(tmp_major_version); + major_version_ = static_cast<major_version_t>(tmp_major_version); + + uint32_t tmp_ttl(0); + is_successful = is_successful && _from->deserialize(tmp_ttl, true); + ttl_ = static_cast<ttl_t>(tmp_ttl); + + uint32_t tmp_minor_version(0); + is_successful = is_successful && _from->deserialize(tmp_minor_version); + minor_version_ = static_cast<minor_version_t>(tmp_minor_version); + + return is_successful; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/subscription.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/subscription.cpp new file mode 100644 index 00000000000..c1ebaefe71c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/subscription.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/subscription.hpp" + +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { +namespace sd { + +major_version_t subscription::get_major() const { + return major_; +} + +void subscription::set_major(major_version_t _major) { + major_ = _major; +} + +ttl_t subscription::get_ttl() const { + return ttl_; +} + +void subscription::set_ttl(ttl_t _ttl) { + ttl_ = _ttl; +} + +std::shared_ptr<endpoint> subscription::get_endpoint(bool _reliable) const { + return _reliable ? reliable_ : unreliable_; +} + +void subscription::set_endpoint(const std::shared_ptr<endpoint>& _endpoint, + bool _reliable) { + if (_reliable) + reliable_ = _endpoint; + else + unreliable_ = _endpoint; +} + +bool subscription::is_selective() const { + return is_selective_; +} +void subscription::set_selective(const bool _is_selective) { + is_selective_ = _is_selective; +} + +subscription_state_e +subscription::get_state(const client_t _client) const { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + auto found_client = clients_.find(_client); + if (found_client != clients_.end()) + return found_client->second; + return subscription_state_e::ST_UNKNOWN; +} + +void +subscription::set_state( + const client_t _client, const subscription_state_e _state) { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + auto found_client = clients_.find(_client); + if (found_client != clients_.end()) + found_client->second = _state; +} + +bool subscription::is_tcp_connection_established() const { + return tcp_connection_established_; +} +void subscription::set_tcp_connection_established(bool _is_established) { + tcp_connection_established_ = _is_established; +} + +bool subscription::is_udp_connection_established() const { + return udp_connection_established_; +} +void subscription::set_udp_connection_established(bool _is_established) { + udp_connection_established_ = _is_established; +} + +bool +subscription::add_client(const client_t _client) { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + auto find_client = clients_.find(_client); + if (find_client != clients_.end()) + return false; + + clients_[_client] = subscription_state_e::ST_UNKNOWN; + return true; +} + +bool +subscription::remove_client(const client_t _client) { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + auto its_size = clients_.size(); + clients_.erase(_client); + return its_size > clients_.size(); +} + +std::set<client_t> subscription::get_clients() const { + std::set<client_t> its_clients; + { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + for (const auto its_item : clients_) + its_clients.insert(its_item.first); + } + return its_clients; +} + +bool subscription::has_client() const { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + return (clients_.size() > 0); +} + +bool subscription::has_client(const client_t _client) const { + std::lock_guard<std::mutex> its_lock(clients_mutex_); + return clients_.find(_client) != clients_.end(); +} + +void subscription::set_eventgroupinfo( + const std::shared_ptr<eventgroupinfo> _info) { + eg_info_ = _info; +} +std::weak_ptr<eventgroupinfo> subscription::get_eventgroupinfo() const { + return eg_info_; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/unknown_option_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/unknown_option_impl.cpp new file mode 100644 index 00000000000..16e88ed627a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/service_discovery/src/unknown_option_impl.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../include/unknown_option_impl.hpp" + +#include "../../message/include/deserializer.hpp" + +namespace vsomeip_v3 { +namespace sd { + +bool sd::unknown_option_impl::deserialize(deserializer * _from) +{ + // Deserialize the header. + if (!option_impl::deserialize(_from)) { + return false; + } + payload_ = std::vector<uint8_t>(length_ - 1); + + // Deserialize the payload. + return _from->deserialize(payload_); +} + +const std::vector<uint8_t>& unknown_option_impl::get_payload() const +{ + return payload_; +} + +} // namespace sd +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/channel_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/channel_impl.hpp new file mode 100644 index 00000000000..f91893ae950 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/channel_impl.hpp @@ -0,0 +1,75 @@ +// Copyright (C) 2017-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TRACE_CHANNEL_IMPL_HPP_ +#define VSOMEIP_V3_TRACE_CHANNEL_IMPL_HPP_ + +#include <atomic> +#include <functional> +#include <map> +#include <mutex> +#include <string> + +#include "enumeration_types.hpp" +#include <vsomeip/trace.hpp> + +namespace vsomeip_v3 { +namespace trace { + +typedef std::function<bool (service_t, instance_t, method_t)> filter_func_t; + +class channel_impl : public channel { +public: + channel_impl(const std::string &_id, const std::string &_name); + + std::string get_id() const; + std::string get_name() const; + + filter_id_t add_filter( + const match_t &_match, + filter_type_e _type); + + filter_id_t add_filter( + const match_t &_match, + bool _is_positive); + + filter_id_t add_filter( + const std::vector<match_t> &_matches, + bool _is_positive); + + filter_id_t add_filter( + const std::vector<match_t> &_matches, + filter_type_e _type); + + filter_id_t add_filter( + const match_t &_from, const match_t &_to, + bool _is_positive); + + filter_id_t add_filter( + const match_t &_from, const match_t &_to, + filter_type_e _type); + + void remove_filter( + filter_id_t _id); + + std::pair<bool, bool> matches(service_t _service, instance_t _instance, method_t _method); + +private: + filter_id_t add_filter_intern(const filter_func_t& _func, filter_type_e _type); + + std::string id_; + std::string name_; + + std::atomic<filter_id_t> current_filter_id_; + + std::map<filter_id_t, std::pair<filter_func_t, bool>> positive_; + std::map<filter_id_t, filter_func_t> negative_; + std::mutex mutex_; // protects positive_ & negative_ +}; + +} // namespace trace +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TRACE_CHANNEL_IMPL_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/connector_impl.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/connector_impl.hpp new file mode 100644 index 00000000000..8ea7d610bed --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/connector_impl.hpp @@ -0,0 +1,88 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TRACE_CONNECTOR_HPP_ +#define VSOMEIP_V3_TRACE_CONNECTOR_HPP_ + +#ifdef USE_DLT +#ifndef ANDROID +#include <dlt/dlt.h> +#endif +#endif + +#include <mutex> +#include <vector> +#include <map> + +#include <boost/shared_ptr.hpp> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/export.hpp> +#include <vsomeip/trace.hpp> + +#include "enumeration_types.hpp" +#include "header.hpp" +#include "../../endpoints/include/buffer.hpp" + +namespace vsomeip_v3 { + +namespace cfg { + struct trace; +} + +namespace trace { + +class channel_impl; + +class connector_impl : public connector { +public: + VSOMEIP_EXPORT static std::shared_ptr<connector_impl> get(); + + VSOMEIP_EXPORT connector_impl(); + VSOMEIP_EXPORT virtual ~connector_impl(); + + VSOMEIP_EXPORT void configure(const std::shared_ptr<cfg::trace> &_configuration); + VSOMEIP_EXPORT void reset(); + + VSOMEIP_EXPORT void set_enabled(const bool _enabled); + VSOMEIP_EXPORT bool is_enabled() const; + + VSOMEIP_EXPORT void set_sd_enabled(const bool _sd_enabled); + VSOMEIP_EXPORT bool is_sd_enabled() const; + + VSOMEIP_EXPORT bool is_sd_message(const byte_t *_data, uint16_t _data_size) const; + + VSOMEIP_EXPORT std::shared_ptr<channel> add_channel(const std::string &_id, + const std::string &_description); + VSOMEIP_EXPORT bool remove_channel(const std::string &_id); + VSOMEIP_EXPORT std::shared_ptr<channel> get_channel(const std::string &_id) const; + + VSOMEIP_EXPORT void trace(const byte_t *_header, uint16_t _header_size, + const byte_t *_data, uint32_t _data_size); + +private: + bool is_enabled_; + bool is_sd_enabled_; + + std::map<std::string, std::shared_ptr<channel_impl>> channels_; + mutable std::mutex channels_mutex_; + + std::shared_ptr<channel_impl> get_channel_impl(const std::string &_id) const; + + std::mutex configure_mutex_; + +#ifdef USE_DLT +#ifndef ANDROID + std::map<std::string, std::shared_ptr<DltContext>> contexts_; + mutable std::mutex contexts_mutex_; +#endif +#endif + +}; + +} // namespace trace +} // namespace vsomeip_v3 + +#endif // VSOMEIP_TC_TRACE_CONNECTOR_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/defines.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/defines.hpp new file mode 100644 index 00000000000..fd5e8f80478 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/defines.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_TRACE_DEFINES_HPP_ +#define VSOMEIP_TRACE_DEFINES_HPP_ + +#define VSOMEIP_TC_DEFAULT_CHANNEL_NAME "Trace Connector Network Logging" +#define VSOMEIP_TC_DEFAULT_FILTER_TYPE "positive" + +#define VSOMEIP_TC_INSTANCE_POS_MIN 8 +#define VSOMEIP_TC_INSTANCE_POS_MAX 9 + +#endif // VSOMEIP_TRACE_DEFINES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/enumeration_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/enumeration_types.hpp new file mode 100644 index 00000000000..9f5f6e8056c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/enumeration_types.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TRACE_ENUMERATION_TYPES_HPP_ +#define VSOMEIP_V3_TRACE_ENUMERATION_TYPES_HPP_ + +namespace vsomeip_v3 { +namespace trace { + +enum class filter_type_e : uint8_t { + NEGATIVE = 0x00, + POSITIVE = 0x01, + HEADER_ONLY = 0x02 +}; + +} // namespace trace +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TRACE_ENUMERATION_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/header.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/header.hpp new file mode 100644 index 00000000000..190a15fe3e4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/include/header.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TRACE_HEADER_HPP_ +#define VSOMEIP_V3_TRACE_HEADER_HPP_ + +#include <memory> + +#include <vsomeip/primitive_types.hpp> + +#include <boost/asio/ip/address_v4.hpp> + +#define VSOMEIP_TRACE_HEADER_SIZE 10 + +namespace vsomeip_v3 { + +class endpoint; + +namespace trace { + +enum class protocol_e : uint8_t { + local = 0x0, + udp = 0x1, + tcp = 0x2, + unknown = 0xFF +}; + +struct header { + bool prepare(const std::shared_ptr<endpoint> &_endpoint, bool _is_sending, + instance_t _instance); + bool prepare(const endpoint* _endpoint, bool _is_sending, + instance_t _instance); + void prepare(const boost::asio::ip::address_v4 &_address, + std::uint16_t _port, protocol_e _protocol, bool _is_sending, + instance_t _instance); + + byte_t data_[VSOMEIP_TRACE_HEADER_SIZE]; +}; + +} // namespace trace +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_TRACE_HEADER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/channel_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/channel_impl.cpp new file mode 100644 index 00000000000..4452d470a8e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/channel_impl.cpp @@ -0,0 +1,307 @@ +// Copyright (C) 2017-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include "../include/channel_impl.hpp" +#include <vsomeip/internal/logger.hpp> + +namespace vsomeip_v3 { +namespace trace { + +const filter_id_t FILTER_ID_ERROR(0); + +channel_impl::channel_impl(const std::string &_id, const std::string &_name) + : id_(_id), name_(_name), current_filter_id_(1) { +} + +std::string channel_impl::get_id() const { + return id_; +} + +std::string channel_impl::get_name() const { + return name_; +} + +filter_id_t channel_impl::add_filter( + const match_t &_match, bool _is_positive) { + filter_type_e its_filter_type = (_is_positive ? + filter_type_e::POSITIVE : filter_type_e::NEGATIVE); + + return add_filter(_match, its_filter_type); +} + +filter_id_t channel_impl::add_filter( + const match_t &_match, filter_type_e _type) { + + // Create a filter function + std::function<bool (service_t, instance_t, method_t)> its_filter_func; + if (std::get<0>(_match) != ANY_SERVICE) { + if (std::get<1>(_match) != ANY_INSTANCE) { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t _s, instance_t _i, method_t _m) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _i + && std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t _s, instance_t _i, method_t) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _i); + }; + } + } else { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t _s, instance_t, method_t _m) { + return (std::get<0>(_match) == _s + && std::get<1>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t _s, instance_t, method_t) { + return (std::get<0>(_match) == _s); + }; + } + } + } else { + if (std::get<1>(_match) != ANY_INSTANCE) { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t, instance_t _i, method_t _m) { + return (std::get<1>(_match) == _i + && std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [_match](service_t, instance_t _i, method_t) { + return (std::get<1>(_match) == _i); + }; + } + } else { + if (std::get<2>(_match) != ANY_METHOD) { + its_filter_func + = [_match](service_t, instance_t, method_t _m) { + return (std::get<2>(_match) == _m); + }; + } else { + its_filter_func + = [](service_t, instance_t, method_t) { + return true; + }; + } + } + } + + return add_filter_intern(its_filter_func, _type); +} + +filter_id_t channel_impl::add_filter( + const std::vector<match_t> &_matches, bool _is_positive) { + filter_type_e its_filter_type = (_is_positive ? + filter_type_e::POSITIVE : filter_type_e::NEGATIVE); + + return add_filter(_matches, its_filter_type); +} + +filter_id_t channel_impl::add_filter( + const std::vector<match_t> &_matches, filter_type_e _type) { + bool has_service(false); + bool has_instance(false); + bool has_method(false); + + for (auto m : _matches) { + if (std::get<0>(m) != ANY_SERVICE) has_service = true; + if (std::get<1>(m) != ANY_INSTANCE) has_instance = true; + if (std::get<2>(m) != ANY_METHOD) has_method = true; + } + + // Create a filter function + std::function<bool (service_t, instance_t, method_t)> its_filter_func; + if (has_service) { + if (has_instance) { + if (has_method) { + its_filter_func + = [_matches](service_t _s, instance_t _i, method_t _m) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t _s, instance_t _i, method_t) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE)) { + return true; + } + } + return false; + }; + } + } else { + if (has_method) { + its_filter_func + = [_matches](service_t _s, instance_t, method_t _m) { + for (const auto &m : _matches) { + if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t _s, instance_t, method_t) { + for (auto &m : _matches) { + if (std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) { + return true; + } + } + return false; + }; + } + } + } else { + if (has_instance) { + if (has_method) { + its_filter_func + = [_matches](service_t, instance_t _i, method_t _m) { + for (auto &m : _matches) { + if ((std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) + && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [_matches](service_t, instance_t _i, method_t) { + for (auto &m : _matches) { + if (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) { + return true; + } + } + return false; + }; + } + } else { + if (has_method) { + its_filter_func + = [_matches](service_t, instance_t, method_t _m) { + for (auto &m : _matches) { + if (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD) { + return true; + } + } + return false; + }; + } else { + its_filter_func + = [](service_t, instance_t, method_t) { + return true; + }; + } + } + } + + return add_filter_intern(its_filter_func, _type); +} + +filter_id_t channel_impl::add_filter( + const match_t &_from, const match_t &_to, filter_type_e _type) { + + // Check usage of ANY_* which is forbidden here + if (std::get<0>(_from) == ANY_SERVICE || + std::get<1>(_from) == ANY_INSTANCE || + std::get<2>(_from) == ANY_METHOD || + std::get<0>(_to) == ANY_SERVICE || + std::get<1>(_to) == ANY_INSTANCE || + std::get<2>(_to) == ANY_METHOD) { + VSOMEIP_ERROR << "Trace filter configuration error: " + "You must not use wildcards in range filters."; + return FILTER_ID_ERROR; + } + + std::function<bool (service_t, instance_t, method_t)> its_filter_func + = [_from, _to](service_t _s, instance_t _i, method_t _m) { + return (std::get<0>(_from) <= _s && _s <= std::get<0>(_to) + && std::get<1>(_from) <= _i && _i <= std::get<1>(_to) + && std::get<2>(_from) <= _m && _m <= std::get<2>(_to)); + }; + + return add_filter_intern(its_filter_func, _type); +} + +filter_id_t channel_impl::add_filter( + const match_t &_from, const match_t &_to, bool _is_positive) { + filter_type_e its_filter_type = (_is_positive ? + filter_type_e::POSITIVE : filter_type_e::NEGATIVE); + + return add_filter(_from, _to, its_filter_type); +} + +void channel_impl::remove_filter(filter_id_t _id) { + std::lock_guard<std::mutex> its_lock(mutex_); + positive_.erase(_id); + negative_.erase(_id); +} + +filter_id_t channel_impl::add_filter_intern(const filter_func_t& _func, filter_type_e _type) { + filter_id_t its_id = current_filter_id_.fetch_add(1); + + std::lock_guard<std::mutex> its_lock(mutex_); + switch(_type) { + case filter_type_e::NEGATIVE : + negative_[its_id] = _func; + break; + case filter_type_e::HEADER_ONLY : + positive_[its_id] = std::make_pair(_func, false); + break; + default : + positive_[its_id] = std::make_pair(_func, true); + } + + return its_id; +} + +std::pair<bool, bool> channel_impl::matches( + service_t _service, instance_t _instance, method_t _method) { + std::lock_guard<std::mutex> its_lock(mutex_); + + // If a negative filter matches --> drop! + for (auto &its_filter : negative_) { + if (its_filter.second(_service, _instance, _method)) + return std::make_pair(false, false); + } + + // If a positive/header-only filter matches --> forward! + bool has_positive(false); + for (auto &its_filter : positive_) { + if (its_filter.second.first(_service, _instance, _method)) + return std::make_pair(true, its_filter.second.second); + + // If we have a positive filter that is no header-only + // filter, set the flag + if (its_filter.second.second) + has_positive = true; + } + + // If no positive filter is defined --> forward! + if (!has_positive) + return std::make_pair(true, true); + + // Default --> Drop! + return std::make_pair(false, false); +} + +} // namespace trace +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/connector_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/connector_impl.cpp new file mode 100644 index 00000000000..02c1032685c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/connector_impl.cpp @@ -0,0 +1,311 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/constants.hpp> +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/runtime.hpp> +#include <chrono> +#include <ctime> +#include <fstream> +#include <iomanip> +#include <iostream> + +#include "../include/channel_impl.hpp" +#include "../include/connector_impl.hpp" +#include "../include/defines.hpp" +#include "../../configuration/include/trace.hpp" +#include "../../utility/include/bithelper.hpp" + +#ifdef ANDROID +#include <utils/Log.h> + +#ifdef ALOGI +#undef ALOGI +#endif + +#define ALOGI(LOG_TAG, ...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) +#ifndef LOGI +#define LOGI ALOGI +#endif + +#endif + +namespace vsomeip_v3 { +namespace trace { + +const char *VSOMEIP_TC_DEFAULT_CHANNEL_ID = "TC"; + +static std::mutex connector_impl_get; + +std::shared_ptr<connector_impl> connector_impl::get() { + std::scoped_lock lk {connector_impl_get}; + static std::shared_ptr<connector_impl> instance = std::make_shared<connector_impl>(); + return instance; +} + +connector_impl::connector_impl() : + is_enabled_(false), + is_sd_enabled_(false) { + + channels_[VSOMEIP_TC_DEFAULT_CHANNEL_ID] + = std::make_shared<channel_impl>(VSOMEIP_TC_DEFAULT_CHANNEL_ID, + VSOMEIP_TC_DEFAULT_CHANNEL_NAME); +#ifdef USE_DLT +#ifndef ANDROID + std::shared_ptr<DltContext> its_default_context + = std::make_shared<DltContext>(); + + contexts_[VSOMEIP_TC_DEFAULT_CHANNEL_ID] = its_default_context; + DLT_REGISTER_CONTEXT_LL_TS(*(its_default_context.get()), + VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME, + DLT_LOG_INFO, DLT_TRACE_STATUS_ON); +#endif +#endif +} + +connector_impl::~connector_impl() { + reset(); +} + +void connector_impl::configure(const std::shared_ptr<cfg::trace> &_configuration) { + std::scoped_lock lk {configure_mutex_}; + if (_configuration) { + is_enabled_ = _configuration->is_enabled_; + is_sd_enabled_ = _configuration->is_sd_enabled_; + } + + if (is_enabled_) { // No need to create filters if tracing is disabled! + for (auto &its_channel : _configuration->channels_) { + if (!add_channel(its_channel->id_, its_channel->name_)) { + VSOMEIP_ERROR << "Channel " << its_channel->id_ + << " has multiple definitions."; + } + } + + for (auto &its_filter : _configuration->filters_) { + for (auto &its_channel : its_filter->channels_) { + auto its_channel_ptr = get_channel_impl(its_channel); + if (its_channel_ptr) { + if (its_filter->is_range_) { + its_channel_ptr->add_filter(its_filter->matches_[0], + its_filter->matches_[1], its_filter->ftype_); + } else { + its_channel_ptr->add_filter(its_filter->matches_, + its_filter->ftype_); + } + } + } + } + } + + VSOMEIP_INFO << "vsomeip tracing " + << (is_enabled_ ? "enabled." : "not enabled.") + << " vsomeip service discovery tracing " + << (is_sd_enabled_ ? "enabled." : "not enabled."); +} + +void connector_impl::reset() { + // reset to default + { + std::scoped_lock its_lock_channels(channels_mutex_); + channels_.clear(); + } +#ifdef USE_DLT +#ifndef ANDROID + { + std::scoped_lock its_contexts_lock(contexts_mutex_); + contexts_.clear(); + } +#endif +#endif +} + +void connector_impl::set_enabled(const bool _enabled) { + is_enabled_ = _enabled; +} + +bool connector_impl::is_enabled() const { + return is_enabled_; +} + +void connector_impl::set_sd_enabled(const bool _sd_enabled) { + is_sd_enabled_ = _sd_enabled; +} + +bool connector_impl::is_sd_enabled() const { + return is_sd_enabled_; +} + +bool connector_impl::is_sd_message(const byte_t *_data, uint16_t _data_size) const { + if (VSOMEIP_METHOD_POS_MAX < _data_size) { + return (_data[VSOMEIP_SERVICE_POS_MIN] == 0xFF && _data[VSOMEIP_SERVICE_POS_MAX] == 0xFF && + _data[VSOMEIP_METHOD_POS_MIN] == 0x81 && _data[VSOMEIP_METHOD_POS_MAX] == 0x00); + } + return false; +} + +std::shared_ptr<channel> connector_impl::add_channel(const trace_channel_t& _id, + const std::string& _name) { + + std::shared_ptr<channel_impl> its_channel; + { + std::scoped_lock its_channels_lock(channels_mutex_); + + // check whether we already know the requested channel + if (channels_.find(_id) != channels_.end()) + return nullptr; + + // create new channel + its_channel = std::make_shared<channel_impl>(_id, _name); + + // add channel + channels_[_id] = its_channel; + } + + // register context +#ifdef USE_DLT +#ifndef ANDROID + { + std::scoped_lock its_contexts_lock(contexts_mutex_); + std::shared_ptr<DltContext> its_context = std::make_shared<DltContext>(); + contexts_[_id] = its_context; + DLT_REGISTER_CONTEXT_LL_TS(*(its_context.get()), _id.c_str(), _name.c_str(), DLT_LOG_INFO, + DLT_TRACE_STATUS_ON); + } +#endif +#endif + + return its_channel; +} + +bool connector_impl::remove_channel(const trace_channel_t &_id) { + + if (_id == VSOMEIP_TC_DEFAULT_CHANNEL_ID) { + // the default channel can not be removed + return false; + } + + bool has_removed {false}; + { + std::scoped_lock its_channels_lock(channels_mutex_); + has_removed = (channels_.erase(_id) == 1); + } + + if (has_removed) { + // unregister context +#ifdef USE_DLT +#ifndef ANDROID + { + std::scoped_lock its_contexts_lock(contexts_mutex_); + auto its_context = contexts_.find(_id); + if (its_context != contexts_.end()) { + DLT_UNREGISTER_CONTEXT(*(its_context->second.get())); + } + } +#endif +#endif + } + + return true; +} + +std::shared_ptr<channel> connector_impl::get_channel(const std::string &_id) const { + std::scoped_lock its_channels_lock(channels_mutex_); + auto its_channel = channels_.find(_id); + return (its_channel != channels_.end() ? its_channel->second : nullptr); +} + +std::shared_ptr<channel_impl> connector_impl::get_channel_impl(const std::string &_id) const { + std::scoped_lock its_channels_lock(channels_mutex_); + auto its_channel = channels_.find(_id); + return (its_channel != channels_.end() ? its_channel->second : nullptr); +} + +void connector_impl::trace(const byte_t *_header, uint16_t _header_size, + const byte_t *_data, uint32_t _data_size) { + +#if USE_DLT + if (!is_enabled_) + return; + + if (_data_size == 0) + return; // no data + + // Clip + uint16_t its_data_size = uint16_t(_data_size > USHRT_MAX ? USHRT_MAX : _data_size); + + if (is_sd_message(_data, its_data_size) && !is_sd_enabled_) + return; // tracing of service discovery messages is disabled! + + service_t its_service = bithelper::read_uint16_be(&_data[VSOMEIP_SERVICE_POS_MIN]); + + // Instance is not part of the SOME/IP header, read it from the trace + // header + instance_t its_instance = bithelper::read_uint16_be(&_header[VSOMEIP_TC_INSTANCE_POS_MIN]); + method_t its_method = bithelper::read_uint16_be(&_data[VSOMEIP_METHOD_POS_MIN]); + +// Forward to channel if the filter set of the channel allows +#ifndef ANDROID + std::scoped_lock its_lock(channels_mutex_, contexts_mutex_); +#else + std::scoped_lock its_lock(channels_mutex_); +#endif + for (auto its_channel : channels_) { + auto ftype = its_channel.second->matches(its_service, its_instance, its_method); + if (ftype.first) { + #ifndef ANDROID + auto its_context = contexts_.find(its_channel.second->get_id()); + if (its_context != contexts_.end()) { + try { + if (ftype.second) { + //Positive Filter + DLT_TRACE_NETWORK_SEGMENTED(*(its_context->second.get()), + DLT_NW_TRACE_IPC, + _header_size, static_cast<void *>(const_cast<byte_t *>(_header)), + its_data_size, static_cast<void *>(const_cast<byte_t *>(_data))); + } else { + //Header-Only Filter + DLT_TRACE_NETWORK_TRUNCATED(*(its_context->second.get()), + DLT_NW_TRACE_IPC, + _header_size, static_cast<void *>(const_cast<byte_t *>(_header)), + VSOMEIP_FULL_HEADER_SIZE, + static_cast<void *>(const_cast<byte_t *>(_data))); + } + } catch (const std::exception& e) { + VSOMEIP_INFO << "connector_impl::trace: " + << "Exception caught when trying to log a trace with DLT. " + << e.what(); + } + } else { + // This should never happen! + VSOMEIP_ERROR << "tracing: found channel without DLT context!"; + } + #else + std::stringstream ss; + ss << "TC:"; + for(int i = 0; i < _header_size; i++) { + ss << ' ' << std::setfill('0') << std::setw(2) << std::hex << int(_header[i]); + } + if (ftype.second) + its_data_size = VSOMEIP_FULL_HEADER_SIZE; + for(int i = 0; i < its_data_size; i++) { + ss << ' ' << std::setfill('0') << std::setw(2) << std::hex << int(_data[i]); + } + std::string app = runtime::get_property("LogApplication"); + + ALOGI(app.c_str(), ss.str().c_str()); + #endif + } + } +#else + (void)_header; + (void)_header_size; + (void)_data; + (void)_data_size; +#endif +} + +} // namespace trace +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/header.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/header.cpp new file mode 100644 index 00000000000..924beab5f48 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/tracing/src/header.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstring> + +#include "../include/header.hpp" +#include "../../endpoints/include/endpoint.hpp" +#include "../../endpoints/include/client_endpoint.hpp" +#include "../../utility/include/bithelper.hpp" + +namespace vsomeip_v3 { +namespace trace { + +bool header::prepare(const std::shared_ptr<endpoint> &_endpoint, + bool _is_sending, instance_t _instance) { + return prepare(_endpoint.get(), _is_sending, _instance); +} + +bool header::prepare(const endpoint *_endpoint, bool _is_sending, + instance_t _instance) { + boost::asio::ip::address its_address; + unsigned short its_port(0); + protocol_e its_protocol(protocol_e::unknown); + + if (_endpoint) { + const client_endpoint* its_client_endpoint = + dynamic_cast<const client_endpoint*>(_endpoint); + if (its_client_endpoint) { + + its_client_endpoint->get_remote_address(its_address); + if (its_address.is_v6()) { + return false; + } + + its_port = its_client_endpoint->get_remote_port(); + + if (_endpoint->is_local()) { + its_protocol = protocol_e::local; + } else { + if (_endpoint->is_reliable()) { + its_protocol = protocol_e::tcp; + } else { + its_protocol = protocol_e::udp; + } + } + } + } + prepare(its_address.to_v4(), its_port, its_protocol, _is_sending, _instance); + return true; +} + +void header::prepare(const boost::asio::ip::address_v4 &_address, + std::uint16_t _port, protocol_e _protocol, + bool _is_sending, instance_t _instance) { + + bithelper::write_uint32_be((uint32_t)_address.to_ulong(), data_); // [0-3] Address + bithelper::write_uint16_be(_port, &data_[4]); // [4-5] Port + data_[6] = static_cast<byte_t>(_protocol); // [6] Protocol + data_[7] = static_cast<byte_t>(_is_sending); // [7] is_sending + bithelper::write_uint16_be(_instance, &data_[8]); // [8-9] Instance +} + +} // namespace trace +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/bithelper.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/bithelper.hpp new file mode 100644 index 00000000000..eae200d3bfd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/bithelper.hpp @@ -0,0 +1,134 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_BITHELPER_HPP +#define VSOMEIP_V3_BITHELPER_HPP + +#include <array> +#include <cstdint> +#include <cstring> +#include <vsomeip/enumeration_types.hpp> +#include <algorithm> + +namespace vsomeip_v3 { + +class bithelper { +public: + bithelper() = delete; + + //Write Methods + inline static void write_uint16_be(uint16_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::be) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + inline static void write_uint16_le(uint16_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::le) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + inline static void write_uint32_be(uint32_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::be) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + inline static void write_uint32_le(uint32_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::le) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + inline static void write_uint64_be(uint64_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::be) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + inline static void write_uint64_le(uint64_t _value, uint8_t* _buffer) { + if (get_endianness() != endianess_e::le) { + _value = swap_endianness(_value); + } + std::memcpy(_buffer, reinterpret_cast<const uint8_t*>(&_value), sizeof(_value)); + } + + //Read Methods + inline static uint16_t read_uint16_be(const uint8_t* _buffer) { + uint16_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::be ? value : swap_endianness(value); + } + + inline static uint16_t read_uint16_le(const uint8_t* _buffer) { + uint16_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::le ? value : swap_endianness(value); + } + + inline static uint32_t read_uint32_be(const uint8_t* _buffer) { + uint32_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::be ? value : swap_endianness(value); + } + + inline static uint32_t read_uint32_le(const uint8_t* _buffer) { + uint32_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::le ? value : swap_endianness(value); + } + + inline static uint64_t read_uint64_be(const uint8_t* _buffer) { + uint64_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::be ? value : swap_endianness(value); + } + + inline static uint64_t read_uint64_le(const uint8_t* _buffer) { + uint64_t value = 0; + std::memcpy(&value, _buffer, sizeof(value)); + return get_endianness() == endianess_e::le ? value : swap_endianness(value); + } + + inline static uint16_t read_high_word(uint32_t input) { + return uint16_t((input >> 16) & 0xFFFF); + } + + inline static uint16_t read_low_word(uint32_t input) { + return uint16_t((input) & 0xFFFF); + } + + template <typename T> + static T swap_endianness(T _value) { + static_assert(std::is_integral<T>::value, "Only integral types can be swapped"); + T swapped{}; + const auto src = reinterpret_cast<unsigned char*>(&_value); + auto dst = reinterpret_cast<unsigned char*>(&swapped); + std::reverse_copy(src, src + sizeof(T), dst); + return swapped; + } + +#if defined(COMPILE_TIME_ENDIAN) && (COMPILE_TIME_ENDIAN == BYTEORDER_LITTLE_ENDIAN) + static constexpr endianess_e get_endianness() { return endianess_e::le; } +#elif defined(COMPILE_TIME_ENDIAN) && (COMPILE_TIME_ENDIAN == BYTEORDER_BIG_ENDIAN) + static constexpr Endianness get_endianness() { return endianess_e::be; } +#else + // Run-time check + static endianess_e get_endianness() { + uint16_t test{0x0102}; + return (*reinterpret_cast<uint8_t*>(&test) == 1) ? endianess_e::be : endianess_e::le; + } +#endif +}; + +} + +#endif // VSOMEIP_V3_BITHELPER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/byteorder.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/byteorder.hpp new file mode 100644 index 00000000000..929033fd627 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/byteorder.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_BYTEORDER_HPP +#define VSOMEIP_V3_BYTEORDER_HPP + +#define BYTEORDER_UNKNOWN 0 +#define BYTEORDER_LITTLE_ENDIAN 1 +#define BYTEORDER_BIG_ENDIAN 2 + +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define COMPILE_TIME_ENDIAN BYTEORDER_LITTLE_ENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define COMPILE_TIME_ENDIAN BYTEORDER_BIG_ENDIAN +# else +# define COMPILE_TIME_ENDIAN BYTEORDER_UNKNOWN +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include <endian.h> +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define COMPILE_TIME_ENDIAN BYTEORDER_LITTLE_ENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define COMPILE_TIME_ENDIAN BYTEORDER_BIG_ENDIAN +# else +# define COMPILE_TIME_ENDIAN BYTEORDER_UNKNOWN +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define COMPILE_TIME_ENDIAN BYTEORDER_LITTLE_ENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define COMPILE_TIME_ENDIAN BYTEORDER_BIG_ENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define COMPILE_TIME_ENDIAN BYTEORDER_BIG_ENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define COMPILE_TIME_ENDIAN BYTEORDER_LITTLE_ENDIAN +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +# define COMPILE_TIME_ENDIAN BYTEORDER_LITTLE_ENDIAN +# else +# define COMPILE_TIME_ENDIAN BYTEORDER_UNKNOWN +# endif + + +#endif // VSOMEIP_V3_BYTEORDER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/criticalsection.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/criticalsection.hpp new file mode 100644 index 00000000000..762c821a85d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/criticalsection.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CRITICALSECTION_HPP +#define VSOMEIP_V3_CRITICALSECTION_HPP + +#include <memory> +#include <mutex> + +namespace vsomeip_v3 { + +#ifdef _WIN32 + + // Windows: CriticalSection uses win32 CRITICAL_SECTION. + // Interface mimics std::mutex so we can use it in + // conjunction with std::unique_lock. + class CriticalSection final { + public: + CriticalSection(); + ~CriticalSection(); + + // prevent copying + CriticalSection(const CriticalSection&) = delete; + CriticalSection& operator=(const CriticalSection&) = delete; + + void lock(); + void unlock(); + bool try_lock(); + + private: + struct Impl; + std::unique_ptr<Impl> m_impl; + }; + +#else + + // Linux: CriticalSection is a type alias for std::mutex. + using CriticalSection = std::mutex; + +#endif + +} // namespace vsomeip_v3 + +#endif //VSOMEIP_V3_CRITICALSECTION_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/qnx_helper.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/qnx_helper.hpp new file mode 100644 index 00000000000..2d390b6fc17 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/qnx_helper.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2020-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef __QNX__ +#ifndef VSOMEIP_V3_QNX_HELPER_HPP_ +#define VSOMEIP_V3_QNX_HELPER_HPP_ +#include <sys/socket.h> +#include <netinet/in.h> + + #define SO_BINDTODEVICE 0x0800 /* restrict traffic to an interface */ + #define IP_PKTINFO 25 /* int; send interface and src addr */ + +/* Structure used for IP_PKTINFO. */ +#ifndef _STRUCT_IN_PKTINFO +struct in_pktinfo + { + int ipi_ifindex; /* Interface index */ + struct in_addr ipi_spec_dst; /* Routing destination address */ + struct in_addr ipi_addr; /* Header destination address */ + }; +#define _STRUCT_IN_PKTINFO +#endif + + #endif // VSOMEIP_V3_QNX_HELPER_HPP_ + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/utility.hpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/utility.hpp new file mode 100644 index 00000000000..58eda288cc7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/include/utility.hpp @@ -0,0 +1,178 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_UTILITY_HPP +#define VSOMEIP_V3_UTILITY_HPP + +#include <atomic> +#include <chrono> +#include <map> +#include <memory> +#include <set> +#include <vector> + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> +#endif + +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/vsomeip_sec.h> + +#include "criticalsection.hpp" + +namespace vsomeip_v3 { + +class configuration; + +class utility { +public: + static inline bool is_request(std::shared_ptr<message> _message) { + return _message ? is_request(_message->get_message_type()) : false; + } + + static inline bool is_request(byte_t _type) { + return is_request(static_cast<message_type_e>(_type)); + } + + static inline bool is_request(message_type_e _type) { + return ((_type < message_type_e::MT_NOTIFICATION) + || (_type >= message_type_e::MT_REQUEST_ACK + && _type <= message_type_e::MT_REQUEST_NO_RETURN_ACK)); + } + + static inline bool is_request_no_return(std::shared_ptr<message> _message) { + return (_message && is_request_no_return(_message->get_message_type())); + } + + static inline bool is_request_no_return(byte_t _type) { + return is_request_no_return(static_cast<message_type_e>(_type)); + } + + static inline bool is_request_no_return(message_type_e _type) { + return (_type == message_type_e::MT_REQUEST_NO_RETURN + || _type == message_type_e::MT_REQUEST_NO_RETURN_ACK); + } + + static inline bool is_response(byte_t _type) { + return is_response(static_cast<message_type_e>(_type)); + } + + static inline bool is_response(message_type_e _type) { + return _type == message_type_e::MT_RESPONSE; + } + + static inline bool is_error(byte_t _type) { + return is_error(static_cast<message_type_e>(_type)); + } + + static inline bool is_error(message_type_e _type) { + return _type == message_type_e::MT_ERROR; + } + + static inline bool is_notification(byte_t _type) { + return is_notification(static_cast<message_type_e>(_type)); + } + + static inline bool is_notification(message_type_e _type) { + return (_type == message_type_e::MT_NOTIFICATION); + } + + static uint64_t get_message_size(const byte_t *_data, size_t _size); + static inline uint64_t get_message_size(std::vector<byte_t> &_data) { + if (_data.size() > 0) { + return get_message_size(&_data[0], _data.size()); + } + return 0; + } + + static uint32_t get_payload_size(const byte_t *_data, uint32_t _size); + + static bool is_routing_manager(const std::string &_network); + static void remove_lockfile(const std::string &_network); + static bool exists(const std::string &_path); + static bool VSOMEIP_IMPORT_EXPORT is_file(const std::string &_path); + static bool VSOMEIP_IMPORT_EXPORT is_folder(const std::string &_path); + + static std::string get_base_path(const std::string &_network); + + static client_t request_client_id(const std::shared_ptr<configuration> &_config, + const std::string &_name, client_t _client); + static void release_client_id(const std::string &_network, + client_t _client); + static std::set<client_t> get_used_client_ids(const std::string &_network); + static void reset_client_ids(const std::string &_network); + + static inline bool is_valid_message_type(message_type_e _type) { + return (_type == message_type_e::MT_REQUEST + || _type == message_type_e::MT_REQUEST_NO_RETURN + || _type == message_type_e::MT_NOTIFICATION + || _type == message_type_e::MT_REQUEST_ACK + || _type == message_type_e::MT_REQUEST_NO_RETURN_ACK + || _type == message_type_e::MT_NOTIFICATION_ACK + || _type == message_type_e::MT_RESPONSE + || _type == message_type_e::MT_ERROR + || _type == message_type_e::MT_RESPONSE_ACK + || _type == message_type_e::MT_ERROR_ACK + || _type == message_type_e::MT_UNKNOWN); + } + + static inline bool is_valid_return_code(return_code_e _code) { + return (_code == return_code_e::E_OK + || _code == return_code_e::E_NOT_OK + || _code == return_code_e::E_UNKNOWN_SERVICE + || _code == return_code_e::E_UNKNOWN_METHOD + || _code == return_code_e::E_NOT_READY + || _code == return_code_e::E_NOT_REACHABLE + || _code == return_code_e::E_TIMEOUT + || _code == return_code_e::E_WRONG_PROTOCOL_VERSION + || _code == return_code_e::E_WRONG_INTERFACE_VERSION + || _code == return_code_e::E_MALFORMED_MESSAGE + || _code == return_code_e::E_WRONG_MESSAGE_TYPE + || (static_cast<std::uint8_t>(_code) >= 0x20 + && static_cast<std::uint8_t>(_code) <= 0x5E)); + } + + static inline bool compare(const vsomeip_sec_client_t &_lhs, + const vsomeip_sec_client_t &_rhs) { + + bool is_equal(false); + if (_lhs.port == _rhs.port) { + if (_lhs.port == VSOMEIP_SEC_PORT_UNUSED) { + is_equal = (_lhs.user == _rhs.user && _lhs.group == _rhs.group); + } else { + is_equal = (_lhs.host == _rhs.host && _lhs.port == _rhs.port); + } + } + return is_equal; + } + + static void set_thread_niceness(int _nice) noexcept; + +private: + struct data_t { + data_t(); + + client_t next_client_; + std::map<client_t, std::string> used_clients_; +#ifdef _WIN32 + HANDLE lock_handle_; +#else + int lock_fd_; +#endif + }; + +private: + static std::uint16_t get_max_client_number( + const std::shared_ptr<configuration> &_config); + + static std::mutex mutex__; + static std::map<std::string, data_t> data__; // network --> data +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_UTILITY_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/criticalsection.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/criticalsection.cpp new file mode 100644 index 00000000000..197ca4d34a9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/criticalsection.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include "../include/criticalsection.hpp" + +#ifdef _WIN32 + +#include <Windows.h> + +namespace vsomeip_v3 { + + struct CriticalSection::Impl final { + CRITICAL_SECTION m_criticalSection; + }; + + + CriticalSection::CriticalSection() + : m_impl(new CriticalSection::Impl()) { + InitializeCriticalSection(&m_impl->m_criticalSection); + } + + CriticalSection::~CriticalSection() { + DeleteCriticalSection(&m_impl->m_criticalSection); + } + + void CriticalSection::lock() { + EnterCriticalSection(&m_impl->m_criticalSection); + } + + bool CriticalSection::try_lock() { + return (TryEnterCriticalSection(&m_impl->m_criticalSection) != 0); + } + + void CriticalSection::unlock(){ + LeaveCriticalSection(&m_impl->m_criticalSection); + } + +} // namespace vsomeip_v3 + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/utility.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/utility.cpp new file mode 100644 index 00000000000..a274a4ce6d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/utility.cpp @@ -0,0 +1,319 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#ifdef _WIN32 + #include <iostream> + #include <tchar.h> + #include <intrin.h> +#else + #include <dlfcn.h> + #include <errno.h> + #include <signal.h> + #include <unistd.h> + #include <fcntl.h> + #include <sys/mman.h> + #include <thread> + #include <sstream> +#endif + +#include <sys/stat.h> + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../include/bithelper.hpp" +#include "../include/utility.hpp" +#include "../../configuration/include/configuration.hpp" + +namespace vsomeip_v3 { + +std::mutex utility::mutex__; +std::map<std::string, utility::data_t> utility::data__; + +utility::data_t::data_t() + : next_client_(VSOMEIP_CLIENT_UNSET), +#ifdef _WIN32 + lock_handle_(INVALID_HANDLE_VALUE) +#else + lock_fd_(-1) +#endif +{} + +uint64_t utility::get_message_size(const byte_t *_data, size_t _size) { + uint64_t its_size(0); + if (VSOMEIP_SOMEIP_HEADER_SIZE <= _size) { + its_size = VSOMEIP_SOMEIP_HEADER_SIZE + + bithelper::read_uint32_be(&_data[4]); + } + return its_size; +} + +uint32_t utility::get_payload_size(const byte_t *_data, uint32_t _size) { + if(_size <= VSOMEIP_FULL_HEADER_SIZE) + return 0; + + uint32_t length_ = bithelper::read_uint32_be(&_data[4]); + + if(length_ <= VSOMEIP_SOMEIP_HEADER_SIZE) + return 0; + + if (_size != (VSOMEIP_SOMEIP_HEADER_SIZE + length_)) + return 0; + + return length_ - VSOMEIP_SOMEIP_HEADER_SIZE; +} + +bool utility::is_routing_manager(const std::string &_network) { + // Only the first caller can become routing manager. + // Therefore, subsequent calls can be immediately answered... + std::lock_guard<std::mutex> its_lock(mutex__); + if (data__.find(_network) != data__.end()) + return false; + + auto r = data__.insert(std::make_pair(_network, data_t())); + if (!r.second) + return false; + +#ifdef _WIN32 + wchar_t its_tmp_folder[MAX_PATH]; + if (GetTempPathW(MAX_PATH, its_tmp_folder)) { + std::wstring its_lockfile(its_tmp_folder); + std::string its_network(_network + ".lck"); + its_lockfile.append(its_network.begin(), its_network.end()); + r.first->second.lock_handle_ = CreateFileW(its_lockfile.c_str(), GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if (r.first->second.lock_handle_ == INVALID_HANDLE_VALUE) { + VSOMEIP_ERROR << __func__ << ": CreateFileW failed: " << std::hex << GetLastError(); + } + } else { + VSOMEIP_ERROR << __func__ << ": Could not get temp folder: " + << std::hex << GetLastError(); + r.first->second.lock_handle_ = INVALID_HANDLE_VALUE; + } + + return (r.first->second.lock_handle_ != INVALID_HANDLE_VALUE); +#else + std::string its_base_path(VSOMEIP_BASE_PATH + _network); + std::string its_lockfile(its_base_path + ".lck"); + int its_lock_ctrl(-1); + + struct flock its_lock_data = { F_WRLCK, SEEK_SET, 0, 0, 0 }; + + r.first->second.lock_fd_ = open(its_lockfile.c_str(), O_WRONLY | O_CREAT, S_IWUSR | S_IWGRP); + if (-1 != r.first->second.lock_fd_) { + its_lock_data.l_pid = getpid(); + its_lock_ctrl = fcntl(r.first->second.lock_fd_, F_SETLK, &its_lock_data); + } else { + VSOMEIP_ERROR << __func__ + << ": Could not open " << its_lockfile << ": " << std::strerror(errno); + } + + return (its_lock_ctrl != -1); +#endif +} + +void utility::remove_lockfile(const std::string &_network) { + std::lock_guard<std::mutex> its_lock(mutex__); + + auto r = data__.find(_network); + if (r == data__.end()) // No need to do anything as automatic + return; + +#ifdef _WIN32 + if (r->second.lock_handle_ != INVALID_HANDLE_VALUE) { + if (CloseHandle(r->second.lock_handle_) == 0) { + VSOMEIP_ERROR << __func__ << ": CloseHandle failed." + << std::hex << GetLastError(); + } + wchar_t its_tmp_folder[MAX_PATH]; + if (GetTempPathW(MAX_PATH, its_tmp_folder)) { + std::wstring its_lockfile(its_tmp_folder); + std::string its_network(_network + ".lck"); + its_lockfile.append(its_network.begin(), its_network.end()); + if (DeleteFileW(its_lockfile.c_str()) == 0) { + VSOMEIP_ERROR << __func__ << ": DeleteFileW failed: " + << std::hex << GetLastError(); + + } + } else { + VSOMEIP_ERROR << __func__ << ": Could not get temp folder." + << std::hex << GetLastError(); + } + } +#else + std::string its_base_path(VSOMEIP_BASE_PATH + _network); + std::string its_lockfile(its_base_path + ".lck"); + + if (r->second.lock_fd_ != -1) { + if (close(r->second.lock_fd_) == -1) { + VSOMEIP_ERROR << __func__ << ": Could not close lock_fd__" + << std::strerror(errno); + } + } + if (remove(its_lockfile.c_str()) == -1) { + VSOMEIP_ERROR << __func__ << ": Could not remove " << its_lockfile + << ": " << std::strerror(errno); + } +#endif + data__.erase(_network); +} + +bool utility::exists(const std::string &_path) { + struct stat its_stat; + return (stat(_path.c_str(), &its_stat) == 0); +} + +bool utility::is_file(const std::string &_path) { + struct stat its_stat; + if (stat(_path.c_str(), &its_stat) == 0) { + if (its_stat.st_mode & S_IFREG) + return true; + } + return false; +} + +bool utility::is_folder(const std::string &_path) { + struct stat its_stat; + if (stat(_path.c_str(), &its_stat) == 0) { + if (its_stat.st_mode & S_IFDIR) + return true; + } + return false; +} + +std::string utility::get_base_path(const std::string &_network) { + return std::string(VSOMEIP_BASE_PATH + _network + "-"); +} + +client_t +utility::request_client_id( + const std::shared_ptr<configuration> &_config, + const std::string &_name, client_t _client) { + std::lock_guard<std::mutex> its_lock(mutex__); + static const std::uint16_t its_max_num_clients = get_max_client_number(_config); + + static const std::uint16_t its_diagnosis_mask = _config->get_diagnosis_mask(); + static const std::uint16_t its_client_mask = static_cast<std::uint16_t>(~its_diagnosis_mask); + static const client_t its_masked_diagnosis_address = static_cast<client_t>( + (_config->get_diagnosis_address() << 8) & its_diagnosis_mask); + static const client_t its_biggest_client = its_masked_diagnosis_address | its_client_mask; + static const client_t its_smallest_client = its_masked_diagnosis_address; + + auto r = data__.find(_config->get_network()); + if (r == data__.end()) + return VSOMEIP_CLIENT_UNSET; + + if (r->second.next_client_ == VSOMEIP_CLIENT_UNSET) { + r->second.next_client_ = its_smallest_client; + } + + if (_client != VSOMEIP_CLIENT_UNSET) { // predefined client identifier + const auto its_iterator = r->second.used_clients_.find(_client); + if (its_iterator == r->second.used_clients_.end()) { // unused identifier + r->second.used_clients_[_client] = _name; + return _client; + } else { // already in use + + // The name matches the assigned name --> return client + // NOTE: THIS REQUIRES A CONSISTENT CONFIGURATION!!! + if (its_iterator->second == _name) { + return _client; + } + + VSOMEIP_WARNING << "Requested client identifier " + << std::setw(4) << std::setfill('0') + << std::hex << _client + << " is already used by application \"" + << its_iterator->second + << "\"."; + // intentionally fall through + } + } + + if (r->second.next_client_ == its_biggest_client) { + // start at beginning of client range again when the biggest client was reached + r->second.next_client_ = its_smallest_client; + } + std::uint16_t increase_count = 0; + do { + r->second.next_client_ = (r->second.next_client_ + & static_cast<std::uint16_t>(~its_client_mask)) // save diagnosis address bits + | (static_cast<std::uint16_t>((r->second.next_client_ // set all diagnosis address bits to one + | static_cast<std::uint16_t>(~its_client_mask)) + 1u) // and add one to the result + & its_client_mask); // set the diagnosis address bits to zero again + if (increase_count++ == its_max_num_clients) { + VSOMEIP_ERROR << __func__ << " no free client IDs left! " + "Max amount of possible concurrent active vsomeip " + "applications reached (" << std::dec << r->second.used_clients_.size() + << ")."; + return VSOMEIP_CLIENT_UNSET; + } + } while (r->second.used_clients_.find(r->second.next_client_) != r->second.used_clients_.end() + || _config->is_configured_client_id(r->second.next_client_)); + + r->second.used_clients_[r->second.next_client_] = _name; + return r->second.next_client_; +} + +void +utility::release_client_id(const std::string &_network, client_t _client) { + std::lock_guard<std::mutex> its_lock(mutex__); + auto r = data__.find(_network); + if (r != data__.end()) + r->second.used_clients_.erase(_client); +} + +std::set<client_t> +utility::get_used_client_ids(const std::string &_network) { + std::lock_guard<std::mutex> its_lock(mutex__); + std::set<client_t> its_used_clients; + auto r = data__.find(_network); + if (r != data__.end()) { + for (const auto& c : r->second.used_clients_) + its_used_clients.insert(c.first); + } + return its_used_clients; +} + +void utility::reset_client_ids(const std::string &_network) { + std::lock_guard<std::mutex> its_lock(mutex__); + auto r = data__.find(_network); + if (r != data__.end()) { + r->second.used_clients_.clear(); + r->second.next_client_ = VSOMEIP_CLIENT_UNSET; + } +} + +void utility::set_thread_niceness(int _nice) noexcept { +#if defined(__linux__) + errno = 0; + if ((nice(_nice) == -1) && (errno < 0)) { + VSOMEIP_WARNING << "failed to set niceness for thread " << std::this_thread::get_id() << " (error: " << strerror(errno) << ')'; + return; + } +#else + (void)_nice; +#endif +} + +std::uint16_t utility::get_max_client_number( + const std::shared_ptr<configuration> &_config) { + std::uint16_t its_max_clients(0); + const int bits_for_clients = +#ifdef _WIN32 + __popcnt( +#else + __builtin_popcount( +#endif + static_cast<std::uint16_t>(~_config->get_diagnosis_mask())); + for (int var = 0; var < bits_for_clients; ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + return its_max_clients; +} + +} // namespace vsomeip_v3 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers.cpp new file mode 100644 index 00000000000..612da27ad20 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef __linux__ + +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/types.h> + +/* + * These definitions MUST remain in the global namespace. + */ +extern "C" +{ + /* + * The real socket(2), renamed by GCC. + */ + int __real_socket(int domain, int type, int protocol) noexcept; + + /* + * Overrides socket(2) to set SOCK_CLOEXEC by default. + */ + int __wrap_socket(int domain, int type, int protocol) noexcept + { + return __real_socket(domain, type | SOCK_CLOEXEC, protocol); + } + + /* + * Overrides accept(2) to set SOCK_CLOEXEC by default. + */ + int __wrap_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) + { + return accept4(sockfd, addr, addrlen, SOCK_CLOEXEC); + } + + /* + * The real open(2), renamed by GCC. + */ + int __real_open(const char *pathname, int flags, mode_t mode); + + /* + * Overrides open(2) to set O_CLOEXEC by default. + */ + int __wrap_open(const char *pathname, int flags, mode_t mode) + { + return __real_open(pathname, flags | O_CLOEXEC, mode); + } +} + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers_qnx.cpp b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers_qnx.cpp new file mode 100644 index 00000000000..b9625a6f66d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/implementation/utility/src/wrappers_qnx.cpp @@ -0,0 +1,161 @@ +// Copyright (C) 2020-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifdef __QNX__ + +#include <sys/socket.h> +#include <sys/types.h> + +#include <fcntl.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <sys/dcmd_ip.h> +#include <sys/netmgr.h> +#include <sys/sockmsg.h> +#include <unistd.h> + +typedef enum accept_msg_t { + ACCEPT1=1, + ACCEPT4, +} accept_msg_t; + +struct _io_sock_accept { + struct _io_openfd msg; + accept_msg_t type; + int flags; + socklen_t anamelen; +}; + +typedef union { + struct _io_sock_accept i; +} io_sock_accept_t; + +static int +__accept (int s, struct sockaddr *addr, socklen_t *addrlen, accept_msg_t msg_type, int flags) +{ + /* This is basically _sopenfd specifying a return buffer for dst address */ + int fd2; + int ret, niov; + io_sock_accept_t msg; + struct _io_openfd *open; + struct _server_info info; + iov_t iov[2]; + socklen_t len; + + if ((addrlen) && (*addrlen > 0) && (!addr)) { + /* Prevent addr dereference */ + errno = EINVAL; + return -1; + } + + if (s == -1 || ConnectServerInfo(0, s, &info) != s) { + errno = EBADF; + return -1; + } + + fd2 = ConnectAttach(info.nd, info.pid, info.chid, 0, _NTO_COF_CLOEXEC | _NTO_COF_INSECURE); + if (fd2 == -1) { + return -1; + } + + open = &msg.i.msg; + memset(open, 0x00, sizeof *open); + open->type = _IO_OPENFD; + open->combine_len = sizeof open; + open->ioflag = 0; + open->sflag = 0; + open->xtype = _IO_OPENFD_ACCEPT; + open->info.pid = getpid(); + open->info.chid = info.chid; + open->info.scoid = info.scoid; + open->info.coid = s; + + msg.i.type = msg_type; + msg.i.flags = flags; + if (addr && addrlen && (*addrlen > 0)) { + /* Only send len > 0 if addr is set (accept1() assumption) */ + len = *addrlen; + } else { + len = 0; + } + msg.i.anamelen = len; + + niov = 0; + SETIOV(iov + niov, &msg.i, sizeof(msg.i)); + niov++; + + if (len > 0) { + /* Only send buffer space required */ + SETIOV(iov + niov, addr, len); + niov++; + } + + ret = MsgSendv(fd2, iov, niov, iov, niov); + if (ret == -1) { + if(errno == ENOSYS) { + errno = ENOTSOCK; + } + ConnectDetach(fd2); + return -1; + } + + if (addr && addrlen && (*addrlen > 0)) { + *addrlen = msg.i.anamelen; + } + + ConnectFlags_r(0, fd2, FD_CLOEXEC, (flags & SOCK_CLOEXEC) ? 1 : 0); + + return fd2; +} + +int +accept4 (int s, struct sockaddr *addr, socklen_t *addrlen, int flags) { + return __accept(s, addr, addrlen, ACCEPT4, flags); +} + +/* + * These definitions MUST remain in the global namespace. + */ +extern "C" +{ + /* + * The real socket(2), renamed by GCC. + */ + int __real_socket(int domain, int type, int protocol) noexcept; + + /* + * Overrides socket(2) to set SOCK_CLOEXEC by default. + */ + int __wrap_socket(int domain, int type, int protocol) noexcept + { + return __real_socket(domain, type | SOCK_CLOEXEC, protocol); + } + + /* + * Overrides accept(2) to set SOCK_CLOEXEC by default. + */ + int __wrap_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) + { + return accept4(sockfd, addr, addrlen, SOCK_CLOEXEC); + } + + /* + * The real open(2), renamed by GCC. + */ + int __real_open(const char *pathname, int flags, mode_t mode); + + /* + * Overrides open(2) to set O_CLOEXEC by default. + */ + int __wrap_open(const char *pathname, int flags, mode_t mode) + { + return __real_open(pathname, flags | O_CLOEXEC, mode); + } +} + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/application.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/application.hpp new file mode 100644 index 00000000000..0d4b671f8e1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/application.hpp @@ -0,0 +1,1093 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_APPLICATION_HPP +#define VSOMEIP_APPLICATION_HPP + +#include <chrono> +#include <memory> +#include <set> +#include <map> +#include <vector> + +#include "../../compat/vsomeip/constants.hpp" +#include "../../compat/vsomeip/enumeration_types.hpp" +#include "../../compat/vsomeip/function_types.hpp" +#include "../../compat/vsomeip/handler.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +class configuration; +class event; +class payload; +struct policy; + +/** + * \defgroup vsomeip + * + * @{ + */ + +/** + * + * \brief This class contains the public API of the vsomeip implementation. + * + * Due to its heavy resource footprint, it should exist once per client and can + * be instantiated using the API of @ref runtime. It manages the lifecycle of + * the vsomeip client and allocates all resources needed to communicate. + * + */ +class application { +public: + virtual ~application() {} + + /** + * + * \brief Returns the name of the application as given during creation + * + * The application name is used to identify the application. It is either + * set explicitely when the application object is created or configured by + * the environment variable VSOMEIP_APPLICATION_NAME. + * + * Note: A user application can use several vsomeip application objects in + * parallel. The application names must be set explicitly in this case + * because VSOMEIP_APPLICATION_NAME only allows to specify a single name. + * + * + * \return Application name + * + */ + virtual const std::string & get_name() const = 0; + + /** + * + * \brief Returns the client identifier that was assigned to the + * application object. + * + * Each request sent by and each response sent to the application contain + * the client identifier as part of the request identifier within the + * SOME/IP message header. The client identifier can either be configured + * by the configured as part of the application node within a vsomeip + * configuration file or is automatically set to an unused client + * identifier by vsomeip. If the client identifier is automatically set, + * its high byte will always match the diagnosis address of the device. + * + * \return Client ID of application + * + */ + virtual client_t get_client() const = 0; + + /** + * + * \brief Does nothing. + * + * This method exists for compatibility reasons only. It is a null + * operation and will be removed with the next major vsomeip version. + * + */ + virtual void set_configuration(const std::shared_ptr<configuration> _configuration) = 0; + + /** + * + * \brief Initializes the application. + * + * The init method must be called first after creating a vsomeip + * application and executes the following steps to initialize it: + * - Loading the configuration from a dynamic module + * - Loading the configuration from a .json file or + * - Loading the configuration from compiled data (not yet available) + * - Determining routing configuration and initialization of the routing + * itself + * - Installing signal handlers + * + */ + virtual bool init() = 0; + + /** + * + * \brief Starts message processing. + * + * This method must be called after init to start message processing. It + * will block until the message processing is terminated using the @ref + * stop method or by receiving signals. It processes messages received + * via the sockets and uses registered callbacks to pass them to the user + * application. + * + */ + virtual void start() = 0; + + /** + * + * \brief Stops message processing. + * + * This method stops message processing. Thus, @ref start will return + * after a call to stop. + * + */ + virtual void stop() = 0; + + /** + * + * \brief Offers a SOME/IP service instance. + * + * The user application must call this method for each service it offers + * to register it at the vsomeip routing component, which makes the + * service visible to interested clients. Dependent on the configuration + * the service is available internally only or internally and externally. + * To offer a service to the external network, the configuration must + * contain a port for the offered service instance. If no such port + * configuration is provided, the service is not visible outside the + * device. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifier of the offered service instance. + * \param _major Major service version (Default: 0). + * \param _minor Minor service version (Default: 0). + * + */ + virtual void offer_service(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = + DEFAULT_MINOR) = 0; + + /** + * + * \brief Stops offering a SOME/IP service instance. + * + * The user application must call this method to withdraw a service offer. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifer of the offered service instance. + * \param _major Major service version (Default: 0). + * \param _minor Minor service version (Default: 0). + * + */ + virtual void stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = + DEFAULT_MINOR) = 0; + + /** + * + * \brief Offers a SOME/IP event or field. + * + * A user application must call this method for each event/field it wants + * to offer. The event is registered at the vsomeip routing component that + * enables other applications to subscribe to the event/field as well as + * to get and set the field value. + * + * \param _service Service identifier of the interface containing the + * event. + * \param _instance Instance identifier of the interface containing the + * event. + * \param _event Event identifier of the offered event. + * \param _eventgroups List of eventgroup identifiers of the eventgroups + * that contain the event. + * \param _is_field Selector for event or field. + * + */ + virtual void offer_event(service_t _service, + instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, + bool _is_field) = 0; + + /** + * + * \brief Stops offering a SOME/IP event or field. + * + * A user application must call this method to withdraw the offer of an + * event or field. + * + * \param _service Service identifier of the interface that contains the + * event + * \param _instance Instance identifier of the interface that contains the + * event + * \param _event Event identifier of the offered event. + * + */ + virtual void stop_offer_event(service_t _service, + instance_t _instance, event_t _event) = 0; + + /** + * + * \brief Registers the application as client of a service instance. + * + * A user application must call this method for each service instance it + * wants to use. The request is stored within the routing component and the + * application is registered as client for the service as soon as the + * service instance becomes available. + * + * \param _service Service identifier of the requested service interface. + * \param _instance Instance identifier of the requested service instance. + * \param _major Major service version (Default: 0xFF). + * \param _minor Minor service version (Default: 0xFFFFFF). + * \param _use_exclusive_proxy Create an IP endpoint that is exclusively + * used for the communication of this application to the service instance. + * + */ + virtual void request_service(service_t _service, instance_t _instance, + major_version_t _major = ANY_MAJOR, + minor_version_t _minor = ANY_MINOR, + bool _use_exclusive_proxy = false) = 0; + + /** + * + * \brief Unregister the application as client of a service instance. + * + * A user application should call this method if it does not request to + * use the service instance any longer. The method unregisters the request + * a the routing component, which removes the service instance from the + * list of requested service instances if the call releases the last + * existing request for the service instance. This is important for + * external service instances, as the SOME/IP Service Discovery can avoid + * to send unnecessary Find messages. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifier of the offered service instance. + * + */ + virtual void release_service(service_t _service, instance_t _instance) = 0; + + /** + * + * \brief Registers the application as user of an event or field. + * + * A user application must call this method before being able to receive + * event or field data. The method registers the event or field at the + * routing component. + * + * \param _service Service identifier of the interface that contains the + * event. + * \param _instance Instance identifier of the interface that contains the + * event. + * \param _event Event identifier of the event. + * \param _eventgroups List of Eventgroup identifiers of the eventgroups + * that contain the event. + * \param _is_field Pure event (false) or field (true). + * + */ + virtual void request_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + bool _is_field) = 0; + /** + * + * \brief Unregister the application as user of an event or field. + * + * Unregister the application as user of an event or field and completely + * removes the event/field if the application is the last existing user. + * + * \param _service Service identifier of the interface that contains the + * event or field. + * \param _instance Instance identifier of the instance that contains the + * event or field. + * \param _event Event identifier of the event or field. + * . + */ + virtual void release_event(service_t _service, instance_t _instance, + event_t _event) = 0; + + /** + * + * \brief Subscribes to an eventgroup. + * + * A user application must call this function to subscribe to an eventgroup. + * Before calling subscribe it must register all events it interested in by + * calls to @ref request_event. The method additionally allows to specify + * a specific event. If a specific event is specified, all other events of + * the eventgroup are not received by the application. + * + * Note: For external services, providing a specific event does not change + * anything regarding the message routing. The specific event is only used + * to filter incoming events and to determine which initial events must be + * sent. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * \param _major Major version number of the service. + * \param _subscription_type Specifies how the events shall be received. + * \param _event All (Default) or a specific event. + * + */ + virtual void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major = DEFAULT_MAJOR, + subscription_type_e _subscription_type = subscription_type_e::SU_RELIABLE_AND_UNRELIABLE, + event_t _event = ANY_EVENT) = 0; + + /** + * + * \brief Unsubscribes from an eventgroup. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * + */ + virtual void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) = 0; + + /** + * + * \brief Retrieve for the availability of a service instance. + * + * If the version is also given, the result will only be true if the + * service instance is available in that specific version. + * + * \param _service Service identifier of the service instance. + * \param _instance Instance identifier of the service instance. + * \param _major Major interface version. Use ANY_MAJOR to ignore the + * major version. + * \param _minor Minor interface version. Use ANY_MINOR to ignore the + * minor version. + * + */ + virtual bool is_available(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) const = 0; + + /** + * + * \brief Sends a message. + * + * Serializes the specified message object, determines the taget and sends + * the message to the target. For requests, the request identifier is + * automatically built from the client identifier and the session + * identifier. + * + * \param _message Message object. + * \param _flush If set to true, the message is immediately sent. Otherwise + * the message might be deferred and sent together with other messages. + * + */ + virtual void send(std::shared_ptr<message> _message, bool _flush = true) = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * + */ + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload) const = 0; + + /** + * + * \brief Fire an event to a specific client. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _client Target client. + * + */ + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client) const = 0; + + /** + * + * \brief Register a state handler with the vsomeip runtime. + * + * The state handler tells if this client is successfully [de]registered + * at the central vsomeip routing component. This is called during the + * @ref start and @ref stop methods of this class to inform the user + * application about the registration state. + * + * \param _handler Handler function to be called on state change. + * + */ + virtual void register_state_handler(state_handler_t _handler) = 0; + + /** + * + * \brief Unregister the state handler. + * + */ + virtual void unregister_state_handler() = 0; + + /** + * + * \brief Registers a handler for the specified method or event. + * + * A user application must call this method to register callbacks for + * for messages that match the specified service, instance, method/event + * pattern. It is possible to specify wildcard values for all three + * identifiers arguments. + * + * Notes: + * - Only a single handler can be registered per service, instance, + * method/event combination. + * - A subsequent call will overwrite an existing registration. + * - Handler registrations containing wildcards can be active in parallel + * to handler registrations for specific service, instance, method/event + * combinations. + * + * \param _service Service identifier of the service that contains the + * method or event. Can be set to ANY_SERVICE to register a handler for + * a message independent from a specific service. + * \param _instance Instance identifier of the service instance that + * contains the method or event. Can be set to ANY_INSTANCE to register + * a handler for a message independent from a specific service. + * \param _method Method/Event identifier of the method/event that is + * to be handled. Can be set to ANY_METHOD to register a handler for + * all methods and events. + * \param _handler Callback that will be called if a message arrives + * that matches the specified service, instance and method/event + * parameters. + * + */ + virtual void register_message_handler(service_t _service, + instance_t _instance, method_t _method, + message_handler_t _handler) = 0; + /** + * + * \brief Unregisters the message handler for the specified service + * method/event notification. + * + * \param _service Service identifier of the service that contains the + * method or event. Can be set to ANY_SERVICE to unregister a handler for + * a message independent from a specific service. + * \param _instance Instance identifier of the service instance that + * contains the method or event. Can be set to ANY_INSTANCE to unregister + * a handler for a message independent from a specific service. + * \param _method Method/Event identifier of the method/event that is + * to be handled. Can be set to ANY_METHOD to unregister a handler for + * all methods and events. + */ + virtual void unregister_message_handler(service_t _service, + instance_t _instance, method_t _method) = 0; + + /** + * + * \brief Register a callback that is called when service instances + * availability changes. + * + * This method allows for the registration of callbacks that are called + * whenever a service appears or disappears. It is possible to specify + * wildcards for service, instance and/or version. Additionally, the + * version specification is optional and defaults to DEFAULT_MAJOR + * /DEFAULT_MINOR. + * + * \param _service Service identifier of the service instance whose + * availability shall be reported. Can be set to ANY_SERVICE. + * \param _instance Instance identifier of the service instance whose + * availability shall be reported. Can be set to ANY_INSTANCE. + * \param _handler Callback to be called if availability changes. + * \param _major Major service version. The parameter defaults to + * DEFAULT_MAJOR and can be set to ANY_MAJOR. + * \param _minor Minor service version. The parameter defaults to + * DEFAULT_MINOR and can be set to ANY_MINOR. + * + */ + virtual void register_availability_handler(service_t _service, + instance_t _instance, availability_handler_t _handler, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0; + + /** + * + * \brief Unregister an availability callback. + * + * \param _service Service identifier of the service instance whose + * availability shall be reported. Can be set to ANY_SERVICE. + * \param _instance Instance identifier of the service instance whose + * availability shall be reported. Can be set to ANY_INSTANCE. + * \param _handler Callback to be called if availability changes. + * \param _major Major service version. The parameter defaults to + * DEFAULT_MAJOR and can be set to ANY_MAJOR. + * \param _minor Minor service version. The parameter defaults to + * DEFAULT_MINOR and can be set to ANY_MINOR. * + */ + virtual void unregister_availability_handler(service_t _service, + instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR) = 0; + + /** + * + * \brief Registers a subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. + * + */ + virtual void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + subscription_handler_t _handler) = 0; + + /** + * + * \brief Unregister a subscription handler. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * + */ + virtual void unregister_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) = 0; + + // [Un]Register handler for subscription errors + /** + * + * \brief Allows for the registration of a subscription error handler. + * + * This handler is called whenever a subscription request for an eventgroup + * was either accepted or rejected. The respective callback is called with + * ether OK (0x00) or REJECTED (0x07). + * + * \param _service Service identifier of service instance whose + * subscription error state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription error state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription error state is to be monitored. + * \param _handler Callback that shall be called. + * + */ + virtual void register_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + error_handler_t _handler) = 0; + + /** + * + * \brief Removes a registered subscription error callback. + * + * \param _service Service identifier of service instance whose + * error callback shall be removed. + * \param _instance Instance identifier of service instance whose + * error callback shall be removed. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * error callback shall be removed. + * + */ + virtual void unregister_subscription_error_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) = 0; + + /** + * + * \brief Unregister all registered handlers. + * + */ + virtual void clear_all_handler() = 0; + + /** + * + * \brief This method tells whether or not this application controls the + * message routing. + * + * The application that controls the routing hosts the routing manager + * and (optionally) loads the Service Discovery component. + * + * \return true, if this is the central routing instance, and false + * otherwise + * + */ + virtual bool is_routing() const = 0; + + /** + * + * \brief Offers a SOME/IP event or field. + * + * A user application must call this method for each event/field it wants + * to offer. The event is registered at the vsomeip routing component that + * enables other applications to subscribe to the event/field as well as + * to get and set the field value. + * + * This version of offer_event adds some additional functionalities: + * - It is possible to configure a cycle time. The notification message of + * this event is then resent cyclically. + * - The parameter _change_resets_cycle is available to control how event + * notification works in case the data is updated by the application. If + * set to true, an update of the data immediately leads to a + * notification. Otherwise, the updated data is sent only after the + * expiration of the cycle time. + * - It is possible to specify callback function that can be used to + * implement a predicate that determines whether or not two event values + * are considered different. Field notifications are only sent if the + * predicate evaluates to true (or if a notify method is called with the + * force flag being set). + * + * \param _service Service identifier of the interface containing the + * event. + * \param _instance Instance identifier of the interface containing the + * event. + * \param _event Event identifier of the offered event. + * \param _eventgroups List of eventgroup identifiers of the eventgroups + * that contain the event. + * \param _is_field Selector for event or field. + * \param _cycle Sets the cycle time of the event. If nonzero, data is + * resent cyclically after the cycle time expired. + * \param _change_resets_cycle Tells if a change immediately leads to + * a notification. + * \param _epsilon_change_func Predicate that determines if two given + * payloads are considered different. + * + * Note: The different versions of offer_event exist for compatibility + * reasons. They will be merged with the next major vsomeip version. + */ + virtual void offer_event(service_t _service, + instance_t _instance, event_t _event, + const std::set<eventgroup_t> &_eventgroups, + bool _is_field, + std::chrono::milliseconds _cycle, + bool _change_resets_cycle, + const epsilon_change_func_t &_epsilon_change_func) = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _force Forces the notification to be sent (even if the event + * is a field and the value did not change). + * + * Note: The different versions of notify do exist for compatibility + * reasons. They will be merged with the next major vsomeip release. + */ + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force) const = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _client Target client. + * \param _force Forces the notification to be sent (even if the event + * is a field and the value did not change). + * + * Note: The different versions of notify_one do exist for compatibility + * reasons. They will be merged with the next major vsomeip release. + */ + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force) const = 0; + + typedef std::map<service_t, std::map<instance_t, std::map<major_version_t, minor_version_t >>> available_t; + /** + * \brief Returns all available instances that match the given combination + * of service, instance and version. + * + * This method checks the availability of the service instances that + * match the specified combination of service, instance and version + * parameters. If at least one matching service instance is available, + * the method returns true, otherwise it returns false. All available + * service instances are returned to the caller by filling the + * _available parameter. + * + * \param _available Map that is filled with the available instances. + * \param _service Service identifier that specifies which service(s) + * are checked. + * \param _instance Instance identifier that specifies which instance(s) + * are checked. + * \param _major_version Major version(s) of the service instances that + * are checked + * \param _minor_version Minor version(s) of the service instance that + * are checked + */ + virtual bool are_available(available_t &_available, + service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _force Forces the notification to be sent (even if the event + * is a field and the value did not change). + * \param _flush Must be set to ensure the event is immediately fired. + * + * Note: The different versions of notify do exist for compatibility + * reasons. They will be merged with the next major vsomeip release. + */ + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force, bool _flush) const = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _client Target client. + * \param _force Forces the notification to be sent (even if the event + * is a field and the value did not change). + * \param _flush Must be set to ensure the event is immediately fired. + * + * Note: The different versions of notify_one do exist for compatibility + * reasons. They will be merged with the next major vsomeip release. + */ + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + client_t _client, bool _force, bool _flush) const = 0; + + /** + * \brief Set the current routing state. + * + * The routing state impacts the behavior of the SOME/IP Service Discovery component. It + * can be set to RUNNING, SUSPENDED, RESUMED, SHUTDOWN or UNKNOWN. Applications only need + * to set the routing state if they are responsible for controlling the routing manager. + * In most environments the vsomeip daemon is controlling the routing manager. + * + * \param _routing_state the current routing state + */ + virtual void set_routing_state(routing_state_e _routing_state) = 0; + + /** + * + * \brief Unsubscribes from an eventgroup. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * \param _event Event to unsubscribe (pass ANY_EVENT for all events of the eventgroup) + */ + virtual void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) = 0; + + + /** + * + * \brief Registers a subscription status listener. + * + * When registered such a handler it will be called for + * every application::subscribe call. + * + * This method is intended to replace the application:: + * register_subscription_error_handler call in future releases. + * + * \param _service Service identifier of the service that is subscribed to. + * \param _instance Instance identifier of the service that is subscribed to. + * \param _eventgroup Eventgroup identifier of the eventgroup is subscribed to. + * \param _event Event indentifier of the event is subscribed to. + * \param _handler A subscription status handler which will be called by vSomeIP + * as a follow of application::subscribe. + */ + virtual void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler) = 0; + + /** + * + * \brief Registers a subscription status listener. + * + * When registered such a handler it will be called for + * every application::subscribe call. + * + * This method is intended to replace the application:: + * register_subscription_error_handler call in future releases. + * + * \param _service Service identifier of the service that is subscribed to. + * \param _instance Instance identifier of the service that is subscribed to. + * \param _eventgroup Eventgroup identifier of the eventgroup is subscribed to. + * \param _event Event indentifier of the event is subscribed to. + * \param _handler A subscription status handler which will be called by vSomeIP + * as a follow of application::subscribe. + * \param _is_selective Flag to enable calling the provided handler if the + * subscription is answered with a SUBSCRIBE_NACK. + */ + virtual void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective) = 0; + + /** + * + * \brief Returns all registered services / instances on this node in an async callback. + * + * When called with a handler of type offered_services_handler_t, + * all at the routing manager registered services on this node get returned in a vector of + * service / instance pairs depending on the given _offer_type. + * + * \param _offer_type type of offered services to be returned (OT_LOCAL = 0x00, OT_REMOTE = 0x01, OT_ALL = 0x02) + * \param offered_services_handler_t handler which gets called with a vector of service instance pairs that are currently offered + */ + virtual void get_offered_services_async(offer_type_e _offer_type, offered_services_handler_t _handler) = 0; + + /** + * + * \brief Sets a handler to be called cyclically for watchdog monitoring. + * + * The handler shall be called in the given interval, but not before start() + * has been called, and not after call to stop() returned. + * + * In case the application is running, i.e. start() succeeded, but the + * handler will not be invoke within the (approximate) interval it may + * be assumed that I/O or internal dispatcher threads are non-functional. + * + * \remark Accuracy of call interval is limited by clock/timer granularity + * or scheduling effects, thus it may underrun or overrun by small + * amount. + * + * \note Only one handler can be active at the time, thus last handler set + * by calling this function will be invoked. + * + * \note To disable calling an active handler, invoke this method again, + * passing nullptr as _handler and/or std::chrono::seconds::zero() + * as _interval. + * + * \param _handler A watchdog handler, pass nullptr to deactivate. + * \param _interval Call interval in seconds, pass std::chrono::seconds::zero() to deactivate. + */ + virtual void set_watchdog_handler(watchdog_handler_t _handler, std::chrono::seconds _interval) = 0; + + /** + * + * \brief Registers a subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. + * + */ + virtual void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_t _handler) = 0; + + /** + * \brief Enables or disables calling of registered offer acceptance + * handler for given IP address + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _address IP address for which offer acceptance handler should be + * called + * \param _path Path which indicates need for offer acceptance + * \param _enable enable or disable calling of offer acceptance handler + */ + virtual void set_offer_acceptance_required(ip_address_t _address, + const std::string _path, + bool _enable) = 0; + + /** + * \brief Returns all configured IP addresses which require calling of + * registered offer acceptance handler + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \return map with known IP addresses requiring offer acceptance handling + */ + typedef std::map<ip_address_t, std::string> offer_acceptance_map_type_t; + virtual offer_acceptance_map_type_t get_offer_acceptance_required() = 0; + + /** + * \brief Registers a handler which will be called upon reception of + * a remote offer with the offering ECU's IP address as parameter + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_offer_acceptance_handler( + offer_acceptance_handler_t _handler) = 0; + + /** + * \brief Registers a handler which will be called upon detection of a + * reboot of a remote ECU with the remote ECU's IP address as a parameter + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_reboot_notification_handler( + reboot_notification_handler_t _handler) = 0; + + /** + * \brief Registers a handler which will be called when the routing reached + * READY state. + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_routing_ready_handler( + routing_ready_handler_t _handler) = 0; + + /** + * \brief Registers a handler which will be called when the routing state + * changes. + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_routing_state_handler( + routing_state_handler_t _handler) = 0; + + /** + * \brief Update service configuration to offer a local service on the + * network as well + * + * This function is intended to take the necessary information to offer a + * service remotely if it was offered only locally beforehand. + * Precondition: The service must already be offered locally before + * calling this method. + * This function only has an effect if called on an application acting as + * routing manager. + * + * \param _service Service identifier + * \param _instance Instance identifier + * \param _port The port number on which the service should be offered + * \param _reliable Offer via TCP or UDP + * \param _magic_cookies_enabled Flag to enable magic cookies + * \param _offer Offer the service or stop offering it remotely + */ + virtual bool update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer) = 0; + + /** + * \brief Update security configuration of routing manager and all local clients + * The given handler gets called with "SU_SUCCESS" if the policy for UID + * and GID was updated or added successfully. If not all clients did confirm + * the update, SU_TIMEOUT is set. + * + * \param _uid UID of the policy + * \param _gid GID of the policy + * \param _policy The security policy to apply + * \param _payload serialized security policy object + * \param _handler handler which gets called after all clients have + * confirmed the policy update + */ + virtual void update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + security_update_handler_t _handler) = 0; + + /** + * \brief Remove a security configuration for routing manager and all local clients + * The given handler gets called with "SU_SUCCESS" if the policy for UID + * and GID was removed successfully. SU_UNKNOWN_USER_ID is set if the + * UID and GID was not found. If not all clients did confirm the removal, + * SU_TIMEOUT is set. + * + * \param _uid UID of the policy to remove + * \param _gid GID of the policy to remove + * \param _handler handler which gets called after all clients have + * confirmed the policy removal + */ + virtual void remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + security_update_handler_t _handler) = 0; +}; + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_APPLICATION_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/constants.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/constants.hpp new file mode 100644 index 00000000000..2d149202d3f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/constants.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_CONSTANTS_HPP +#define VSOMEIP_CONSTANTS_HPP + +#include <string> + +#include "../../compat/vsomeip/enumeration_types.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +const major_version_t DEFAULT_MAJOR = 0x00; +const minor_version_t DEFAULT_MINOR = 0x00000000; +const ttl_t DEFAULT_TTL = 0xFFFFFF; // "until next reboot" + +const std::string DEFAULT_MULTICAST = "224.0.0.0"; +const uint16_t DEFAULT_PORT = 30500; +const uint16_t ILLEGAL_PORT = 0xFFFF; + +const uint16_t NO_TRACE_FILTER_EXPRESSION = 0x0000; + +const service_t ANY_SERVICE = 0xFFFF; +const instance_t ANY_INSTANCE = 0xFFFF; +const method_t ANY_METHOD = 0xFFFF; +const major_version_t ANY_MAJOR = 0xFF; +const minor_version_t ANY_MINOR = 0xFFFFFFFF; + +const eventgroup_t DEFAULT_EVENTGROUP = 0x0001; + +const client_t ILLEGAL_CLIENT = 0x0000; + +const byte_t MAGIC_COOKIE_CLIENT_MESSAGE = 0x00; +const byte_t MAGIC_COOKIE_SERVICE_MESSAGE = 0x80; +const length_t MAGIC_COOKIE_SIZE = 0x00000008; +const request_t MAGIC_COOKIE_REQUEST = 0xDEADBEEF; +const client_t MAGIC_COOKIE_NETWORK_BYTE_ORDER = 0xADDE; +const protocol_version_t MAGIC_COOKIE_PROTOCOL_VERSION = 0x01; +const interface_version_t MAGIC_COOKIE_INTERFACE_VERSION = 0x01; +const message_type_e MAGIC_COOKIE_CLIENT_MESSAGE_TYPE = + message_type_e::MT_REQUEST_NO_RETURN; +const message_type_e MAGIC_COOKIE_SERVICE_MESSAGE_TYPE = + message_type_e::MT_NOTIFICATION; +const return_code_e MAGIC_COOKIE_RETURN_CODE = return_code_e::E_OK; + +const byte_t CLIENT_COOKIE[] = { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x01, 0x01, 0x00 }; + +const byte_t SERVICE_COOKIE[] = { 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x01, 0x02, 0x00 }; + +const event_t ANY_EVENT = 0xFFFF; +const client_t ANY_CLIENT = 0xFFFF; + +const pending_subscription_id_t DEFAULT_SUBSCRIPTION = 0x0; +const pending_security_update_id_t DEFAULT_SECURITY_UPDATE_ID = 0x0; + +} // namespace vsomeip + +#endif // VSOMEIP_CONSTANTS_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/defines.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/defines.hpp new file mode 100644 index 00000000000..0442faea24d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/defines.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_DEFINES_HPP +#define VSOMEIP_DEFINES_HPP + +#define VSOMEIP_PROTOCOL_VERSION 0x1 + +// 0 = unlimited, if not specified otherwise via configuration file +#define VSOMEIP_MAX_LOCAL_MESSAGE_SIZE 0 +// 0 = unlimited, if not specified otherwise via configuration file +#define VSOMEIP_MAX_TCP_MESSAGE_SIZE 0 +#define VSOMEIP_MAX_UDP_MESSAGE_SIZE 1416 + +#define VSOMEIP_PACKET_SIZE VSOMEIP_MAX_UDP_MESSAGE_SIZE + +#define VSOMEIP_SOMEIP_HEADER_SIZE 8 +#define VSOMEIP_SOMEIP_MAGIC_COOKIE_SIZE 8 +#define VSOMEIP_FULL_HEADER_SIZE 16 + +#define VSOMEIP_SERVICE_POS_MIN 0 +#define VSOMEIP_SERVICE_POS_MAX 1 +#define VSOMEIP_METHOD_POS_MIN 2 +#define VSOMEIP_METHOD_POS_MAX 3 +#define VSOMEIP_EVENT_POS_MIN 2 +#define VSOMEIP_EVENT_POS_MAX 3 +#define VSOMEIP_LENGTH_POS_MIN 4 +#define VSOMEIP_LENGTH_POS_MAX 7 +#define VSOMEIP_CLIENT_POS_MIN 8 +#define VSOMEIP_CLIENT_POS_MAX 9 +#define VSOMEIP_SESSION_POS_MIN 10 +#define VSOMEIP_SESSION_POS_MAX 11 +#define VSOMEIP_PROTOCOL_VERSION_POS 12 +#define VSOMEIP_INTERFACE_VERSION_POS 13 +#define VSOMEIP_MESSAGE_TYPE_POS 14 +#define VSOMEIP_RETURN_CODE_POS 15 +#define VSOMEIP_PAYLOAD_POS 16 + +#endif // VSOMEIP_DEFINES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/enumeration_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/enumeration_types.hpp new file mode 100644 index 00000000000..71ff38afbc0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/enumeration_types.hpp @@ -0,0 +1,81 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_ENUMERATION_TYPES_HPP +#define VSOMEIP_ENUMERATION_TYPES_HPP + +#include <cstdint> + +namespace vsomeip { + +enum class state_type_e : uint8_t { + ST_REGISTERED = 0x0, + ST_DEREGISTERED = 0x1 +}; + +// SIP_RPC_684 +enum class message_type_e : uint8_t { + MT_REQUEST = 0x00, + MT_REQUEST_NO_RETURN = 0x01, + MT_NOTIFICATION = 0x02, + MT_REQUEST_ACK = 0x40, + MT_REQUEST_NO_RETURN_ACK = 0x41, + MT_NOTIFICATION_ACK = 0x42, + MT_RESPONSE = 0x80, + MT_ERROR = 0x81, + MT_RESPONSE_ACK = 0xC0, + MT_ERROR_ACK = 0xC1, + MT_UNKNOWN = 0xFF +}; + +// SIP_RPC_371 +enum class return_code_e : uint8_t { + E_OK = 0x00, + E_NOT_OK = 0x01, + E_UNKNOWN_SERVICE = 0x02, + E_UNKNOWN_METHOD = 0x03, + E_NOT_READY = 0x04, + E_NOT_REACHABLE = 0x05, + E_TIMEOUT = 0x06, + E_WRONG_PROTOCOL_VERSION = 0x07, + E_WRONG_INTERFACE_VERSION = 0x08, + E_MALFORMED_MESSAGE = 0x09, + E_WRONG_MESSAGE_TYPE = 0xA, + E_UNKNOWN = 0xFF +}; + +enum class subscription_type_e : uint8_t { + SU_RELIABLE_AND_UNRELIABLE = 0x00, + SU_PREFER_UNRELIABLE = 0x01, + SU_PREFER_RELIABLE = 0x02, + SU_UNRELIABLE = 0x03, + SU_RELIABLE = 0x04, +}; + +enum class routing_state_e : uint8_t { + RS_RUNNING = 0x00, + RS_SUSPENDED = 0x01, + RS_RESUMED = 0x02, + RS_SHUTDOWN = 0x03, + RS_DIAGNOSIS = 0x04, + RS_UNKNOWN = 0xFF +}; + +enum class offer_type_e : uint8_t { + OT_LOCAL = 0x00, + OT_REMOTE = 0x01, + OT_ALL = 0x02, +}; + +enum class security_update_state_e : uint8_t { + SU_SUCCESS = 0x00, + SU_NOT_ALLOWED = 0x01, + SU_UNKNOWN_USER_ID = 0x02, + SU_INVALID_FORMAT = 0x03 +}; + +} // namespace vsomeip + +#endif // VSOMEIP_ENUMERATION_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/error.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/error.hpp new file mode 100644 index 00000000000..175f2655fca --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/error.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_ERROR_HPP +#define VSOMEIP_ERROR_HPP + +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +enum class error_code_e : uint8_t { + CONFIGURATION_MISSING, + PORT_CONFIGURATION_MISSING, + CLIENT_ENDPOINT_CREATION_FAILED, + SERVER_ENDPOINT_CREATION_FAILED, + SERVICE_PROPERTY_MISMATCH +}; + +extern const char *ERROR_INFO[]; + +} // namespace vsomeip + +#endif // VSOMEIP_ERROR_HPP + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/export.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/export.hpp new file mode 100644 index 00000000000..a8577eec5d2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/export.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef __EXPORT__HPP__ +#define __EXPORT__HPP__ + +#if _WIN32 + #define VSOMEIP_EXPORT __declspec(dllexport) + #define VSOMEIP_EXPORT_CLASS_EXPLICIT + + #if VSOMEIP_DLL_COMPILATION + #define VSOMEIP_IMPORT_EXPORT __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT __declspec(dllimport) + #endif + + #if VSOMEIP_DLL_COMPILATION_CONFIG + #define VSOMEIP_IMPORT_EXPORT_CONFIG __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT_CONFIG __declspec(dllimport) + #endif +#else + #define VSOMEIP_EXPORT + #define VSOMEIP_IMPORT_EXPORT + #define VSOMEIP_IMPORT_EXPORT_CONFIG +#endif + +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/function_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/function_types.hpp new file mode 100644 index 00000000000..aa086ddc0cc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/function_types.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_FUNCTION_TYPES_HPP +#define VSOMEIP_FUNCTION_TYPES_HPP + +#include <functional> +#include <memory> + +namespace vsomeip { + +class payload; + +typedef std::function< + bool (const std::shared_ptr<payload> &, + const std::shared_ptr<payload> &) > epsilon_change_func_t; + +} // namespace vsomeip + +#endif // VSOMEIP_FUNCTION_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/handler.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/handler.hpp new file mode 100644 index 00000000000..4c742556a31 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/handler.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_HANDLER_HPP +#define VSOMEIP_HANDLER_HPP + +#include <functional> +#include <memory> + +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +class message; + +typedef std::function< void (state_type_e) > state_handler_t; +typedef std::function< void (const std::shared_ptr< message > &) > message_handler_t; +typedef std::function< void (service_t, instance_t, bool) > availability_handler_t; +typedef std::function< bool (client_t, bool) > subscription_handler_t; +typedef std::function< void (const uint16_t) > error_handler_t; +typedef std::function< void (const service_t, const instance_t, const eventgroup_t, + const event_t, const uint16_t) > subscription_status_handler_t; +typedef std::function< void (client_t, bool, std::function< void (const bool) > )> async_subscription_handler_t; + +typedef std::function< void (const std::vector<std::pair<service_t, instance_t>> &_services) > offered_services_handler_t; +typedef std::function< void () > watchdog_handler_t; + +struct ip_address_t { + union { + ipv4_address_t v4_; + ipv6_address_t v6_; + } address_; + bool is_v4_; + + bool operator<(const ip_address_t& _other) const { + if (is_v4_ && _other.is_v4_) { + return address_.v4_ < _other.address_.v4_; + } else if (!is_v4_ && !_other.is_v4_) { + return address_.v6_ < _other.address_.v6_; + } else if (is_v4_ && !_other.is_v4_) { + return true; + } else { + return false; + } + } + + bool operator==(const ip_address_t& _other) const { + if (is_v4_ && _other.is_v4_) { + return address_.v4_ == _other.address_.v4_; + } else if (!is_v4_ && !_other.is_v4_) { + return address_.v6_ == _other.address_.v6_; + } else { + return false; + } + } + + bool operator!=(const ip_address_t& _other) const { + return !(*this == _other); + } + +}; +typedef std::function<bool(const ip_address_t&)> offer_acceptance_handler_t; +typedef std::function<void(const ip_address_t&)> reboot_notification_handler_t; +typedef std::function<void()> routing_ready_handler_t; +typedef std::function<void(routing_state_e)> routing_state_handler_t; +typedef std::function<void(security_update_state_e)> security_update_handler_t; + +} // namespace vsomeip + +#endif // VSOMEIP_HANDLER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/deserializable.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/deserializable.hpp new file mode 100644 index 00000000000..10ead1900bd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/deserializable.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_DESERIALIZABLE_HPP +#define VSOMEIP_DESERIALIZABLE_HPP + +#include "../../../compat/vsomeip/export.hpp" + +namespace vsomeip { + +class deserializer; + +class deserializable { +public: + VSOMEIP_EXPORT virtual ~deserializable() { + } + VSOMEIP_EXPORT virtual bool deserialize(deserializer *_from) = 0; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_SERIALIZABLE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/serializable.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/serializable.hpp new file mode 100644 index 00000000000..8363f4be434 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/internal/serializable.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_SERIALIZABLE_HPP +#define VSOMEIP_SERIALIZABLE_HPP + +#include "../../../compat/vsomeip/export.hpp" + +namespace vsomeip { + +class serializer; + +/** + * Abstract base class for element that can be serialized. + */ +class serializable { +public: + VSOMEIP_EXPORT virtual ~serializable() {} + + /** + * \brief serialize the content of the object + */ + VSOMEIP_EXPORT virtual bool serialize(serializer *_to) const = 0; +}; + +} // namespace vsomeip + +#endif // VSOMEIP_SERIALIZABLE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message.hpp new file mode 100644 index 00000000000..b7049eea648 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_MESSAGE_HPP +#define VSOMEIP_MESSAGE_HPP + +#include <memory> + +#include "../../compat/vsomeip/message_base.hpp" + +namespace vsomeip { + +class payload; + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * \brief Implements regular SOME/IP messages. + * + * This class extends @ref message_base by an unstructured payload. Except + * SOME/IP Service Discovery messages, all SOME/IP messages within vsomeip + * are represented by message objects. + */ + +class message: virtual public message_base { +public: + virtual ~message() {} + + /** + * \brief Returns a pointer to the message payload. + */ + virtual std::shared_ptr<payload> get_payload() const = 0; + + /** + * \brief Set the message payload. + */ + virtual void set_payload(std::shared_ptr<payload> _payload) = 0; +}; + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_MESSAGE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message_base.hpp new file mode 100644 index 00000000000..ffc81fbefea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/message_base.hpp @@ -0,0 +1,211 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_MESSAGE_BASE_HPP +#define VSOMEIP_MESSAGE_BASE_HPP + +#include "../../compat/vsomeip/enumeration_types.hpp" +#include "../../compat/vsomeip/export.hpp" +#include "../../compat/vsomeip/internal/deserializable.hpp" +#include "../../compat/vsomeip/internal/serializable.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * \brief Base class to implement SOME/IP messages. + * + * This class implements the SOME/IP message header and connects to the + * serialzing/deserializing functionalities. The class is inherited by + * the message classes within ::vsomeip and vsomeip::sd that add the + * payload representations for regular and Service Discovery messages. + */ +class message_base + : public serializable, + public deserializable { +public: + VSOMEIP_EXPORT virtual ~message_base() {}; + + /** + * \brief Returns the message identifier. + * + * The method returns the message identifier that consists of + * service identifier and method identifier. + */ + VSOMEIP_EXPORT virtual message_t get_message() const = 0; + /** + * \brief Set the message identifier. + * + * The methods sets service identifier and method identifier in + * a single call. + * + * \param _message The new message identifier. + */ + VSOMEIP_EXPORT virtual void set_message(message_t _message) = 0; + + /** + * \brief Returns the service identifier from the message header. + */ + VSOMEIP_EXPORT virtual service_t get_service() const = 0; + + /** + * \brief Set the service identifier in the message header. + */ + VSOMEIP_EXPORT virtual void set_service(service_t _service) = 0; + + /** + * \brief Returns the instance identifier. + * + * The instance identifier is _not_ part of the SOME/IP header. It is + * either derived from the incoming message (local) or from the port + * that was used to send a message (external). + */ + VSOMEIP_EXPORT virtual instance_t get_instance() const = 0; + + /** + * \brief Set the instance identifier in the message header. + * + * To address the correct service instance, vsomeip uses the instance + * identifier. For external services it is mapped to a IP address and port + * combination before the message is sent. For internal messages is + * transferred as additional data appended to the SOME/IP messages. + * Therefore, before sending a message, a user application must set the + * instance identifier. + */ + VSOMEIP_EXPORT virtual void set_instance(instance_t _instance) = 0; + + /** + * \brief Get the method/event identifier from the message header. + */ + VSOMEIP_EXPORT virtual method_t get_method() const = 0; + + /** + * \brief Set the method/event identifier in the message header. + */ + VSOMEIP_EXPORT virtual void set_method(method_t _method) = 0; + + /** + * \brief Get the payload length from the message header. + */ + VSOMEIP_EXPORT virtual length_t get_length() const = 0; + + /** + * \brief Get the request identifier from the message header. + * + * The request identifier consists of the client identifier and the + * session identifier. As it does really make sense to set it as + * a whole, setting is not supported. + */ + VSOMEIP_EXPORT virtual request_t get_request() const = 0; + + /** + * \brief Set the client identifier in the message header. + */ + VSOMEIP_EXPORT virtual client_t get_client() const = 0; + + /** + * \brief Set the client identifier in the message header. + * + * For requests this is automatically done by @ref application::send. + * For notications this is not needed. + */ + VSOMEIP_EXPORT virtual void set_client(client_t _client) = 0; + + /** + * \brief Get the session identifier from the message header. + */ + VSOMEIP_EXPORT virtual session_t get_session() const = 0; + + /** + * \brief Set the session identifier in the message header. + * + * For requests this is automatically done by @ref application::send + * For notifications it is not needed to set the session identifier. + */ + VSOMEIP_EXPORT virtual void set_session(session_t _session) = 0; + + /** + * \brief Get the protocol version from the message header. + * + * As the protocol version is a fixed value for a vsomeip implementation, + * it cannot be set. + */ + VSOMEIP_EXPORT virtual protocol_version_t get_protocol_version() const = 0; + + /** + * \brief Get the interface version from the message header. + */ + VSOMEIP_EXPORT virtual interface_version_t get_interface_version() const = 0; + + /** + * \brief Set the interface version in the message header. + */ + VSOMEIP_EXPORT virtual void set_interface_version(interface_version_t _version) = 0; + + /** + * \brief Get the message type from the message header. + */ + VSOMEIP_EXPORT virtual message_type_e get_message_type() const = 0; + + /** + * \brief Set the message type in the message header. + */ + VSOMEIP_EXPORT virtual void set_message_type(message_type_e _type) = 0; + + /** + * \brief Get the return code from the message header. + */ + VSOMEIP_EXPORT virtual return_code_e get_return_code() const = 0; + + /** + * \brief Set the return code in the message header. + */ + VSOMEIP_EXPORT virtual void set_return_code(return_code_e _code) = 0; + + /** + * \brief Return the transport mode that was/will be used to send the message. + */ + VSOMEIP_EXPORT virtual bool is_reliable() const = 0; + + /** + * \brief Set the transport mode that will be used to send the message. + */ + VSOMEIP_EXPORT virtual void set_reliable(bool _is_reliable) = 0; + + /** + * \brief Return whether or not the message is an initial event. + */ + VSOMEIP_EXPORT virtual bool is_initial() const = 0; + + /** + * \brief Set whether or not the message is an initial event. + */ + VSOMEIP_EXPORT virtual void set_initial(bool _is_initial) = 0; + + /** + * \brief Return whether or not the CRC value received is valid. + */ + VSOMEIP_EXPORT virtual bool is_valid_crc() const = 0; + + /** + * \brief Set whether or not the CRC value received is valid. + */ + VSOMEIP_EXPORT virtual void set_is_valid_crc(bool _is_valid_crc) = 0; + +}; + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_MESSAGE_BASE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/payload.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/payload.hpp new file mode 100644 index 00000000000..e604a3d46b7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/payload.hpp @@ -0,0 +1,105 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_PAYLOAD_HPP +#define VSOMEIP_PAYLOAD_HPP + +#include <vector> + +#include "../../compat/vsomeip/export.hpp" +#include "../../compat/vsomeip/internal/deserializable.hpp" +#include "../../compat/vsomeip/internal/serializable.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * + * \brief This class implements an array of bytes to be used as + * payload for SOME/IP messages. + * +*/ +class payload: public serializable, public deserializable { +public: + VSOMEIP_EXPORT virtual ~payload() {} + + /** + * \brief Returns true if the given payload is equal to this one. + * + * \param _other Payload that shall be compared to this payload. + */ + VSOMEIP_EXPORT virtual bool operator ==(const payload &_other) = 0; + + /** + * \brief Returns pointer to the payload content + */ + VSOMEIP_EXPORT virtual byte_t * get_data() = 0; + + /** + * \brief Returns constant pointer to the payload content + */ + VSOMEIP_EXPORT virtual const byte_t * get_data() const = 0; + + /** + * \brief Copies the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer remains untouched. + * + * \param _data Pointer to a data buffer. + * \param _length Length of the data buffer. + */ + VSOMEIP_EXPORT virtual void set_data(const byte_t *_data, + length_t _length) = 0; + + /** + * \brief Copies the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer remains untouched. + * + * \param _data Vector containing the data + */ + VSOMEIP_EXPORT virtual void set_data( + const std::vector<byte_t> &_data) = 0; + + /** + * \brief Returns the length of the payload content. + */ + VSOMEIP_EXPORT virtual length_t get_length() const = 0; + + /** + * \brief Set the maximum length of the payload content. + * + * This function must be called before directly copying data using the + * pointer to the internal buffer. + */ + VSOMEIP_EXPORT virtual void set_capacity(length_t _length) = 0; + + /** + * \brief Moves the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer is owned by the payload object afterwards. + * + * \param _data Vector containing the data + */ + VSOMEIP_EXPORT virtual void set_data( + std::vector<byte_t> &&_data) = 0; +}; + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_PAYLOAD_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugin.hpp new file mode 100644 index 00000000000..4d608f17707 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugin.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_PLUGIN_HPP +#define VSOMEIP_PLUGIN_HPP + +#include <memory> + +#if WIN32 + #if VSOMEIP_DLL_COMPILATION_PLUGIN + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllimport) + #endif +#else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN +#endif + +#define VSOMEIP_PLUGIN_INIT_SYMBOL "vsomeip_plugin_init" + +namespace vsomeip { + +enum class plugin_type_e : uint8_t { + APPLICATION_PLUGIN, + PRE_CONFIGURATION_PLUGIN, + CONFIGURATION_PLUGIN, + SD_RUNTIME_PLUGIN +}; + +class plugin; +typedef std::shared_ptr<plugin> (*create_plugin_func)(); +typedef create_plugin_func (*plugin_init_func)(); + +/** + * Base class for all plug-ins + */ +class VSOMEIP_IMPORT_EXPORT_PLUGIN plugin { +public: + virtual ~plugin() {} + + virtual uint32_t get_plugin_version() const = 0; + virtual const std::string &get_plugin_name() const = 0; + virtual plugin_type_e get_plugin_type() const = 0; +}; + +template<class Plugin_> +class plugin_impl : public plugin { +public: + static std::shared_ptr<plugin> get_plugin() { + return std::make_shared<Plugin_>(); + } + + plugin_impl(const std::string &_name, uint32_t _version, + plugin_type_e _type) { + name_ = _name; + version_ = _version; + type_ = _type; + } + + const std::string &get_plugin_name() const { + return name_; + } + + uint32_t get_plugin_version() const { + return version_; + } + + plugin_type_e get_plugin_type() const { + return type_; + } + +private: + uint32_t version_; + std::string name_; + plugin_type_e type_; +}; + +#define VSOMEIP_PLUGIN(class_name) \ + extern "C" { \ + VSOMEIP_EXPORT vsomeip::create_plugin_func vsomeip_plugin_init() { \ + return class_name::get_plugin; \ + } \ + } + +} // namespace vsomeip + +#endif // VSOMEIP_PLUGIN_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/application_plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/application_plugin.hpp new file mode 100644 index 00000000000..7f0bb4a8c77 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/application_plugin.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_APPLICATION_PLUGIN_HPP +#define VSOMEIP_APPLICATION_PLUGIN_HPP + +#include <string> +#include <memory> + +#include "../../../compat/vsomeip/export.hpp" + +// Version should be incremented on breaking API change +#define VSOMEIP_APPLICATION_PLUGIN_VERSION 1 + +namespace vsomeip { + +enum class application_plugin_state_e : uint8_t { + STATE_INITIALIZED, + STATE_STARTED, + STATE_STOPPED +}; + +/** + * The application plug-in can be used to extend application behavior + * via an module/plug-in. + */ +class application_plugin { +public: + virtual ~application_plugin() {} + + // Called by vSomeIP to inform an application plug-in about its actual state + // Call should not be blocked from plug-in as there is no threading. + // The caller thread of "application::init/::start/::stop" will inform the plug-in. + virtual void on_application_state_change(const std::string _application_name, + const application_plugin_state_e _app_state) = 0; +}; + +} + +#endif // VSOMEIP_APPLICATION_PLUGIN_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/pre_configuration_plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/pre_configuration_plugin.hpp new file mode 100644 index 00000000000..bce60b06fe2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/plugins/pre_configuration_plugin.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP +#define VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP + +#include "../../../compat/vsomeip/export.hpp" + +// Version should be incremented on breaking API change +#define VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION 1 + +namespace vsomeip { +/** + * The pre configuration plug-in can be used to extend configuration load behavior + * via an module/plug-in. + */ +class pre_configuration_plugin { +public: + virtual ~pre_configuration_plugin() {} + + // Plug-In should return a valid path to a vSomeIP configuration. + // vSomeIP will use this path for config loading if such a plug-in is availablel. + virtual std::string get_configuration_path() = 0; +}; +} + +#endif // VSOMEIP_PRE_CONFIGURATION_PLUGIN_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/primitive_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/primitive_types.hpp new file mode 100644 index 00000000000..ce1d4bd1030 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/primitive_types.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_PRIMITIVE_TYPES_HPP +#define VSOMEIP_PRIMITIVE_TYPES_HPP + +#include <array> +#include <cstdint> + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <sys/types.h> +#endif + +namespace vsomeip { + +typedef uint32_t message_t; +typedef uint16_t service_t; +typedef uint16_t method_t; +typedef uint16_t event_t; + +typedef uint16_t instance_t; +typedef uint16_t eventgroup_t; + +typedef uint8_t major_version_t; +typedef uint32_t minor_version_t; + +typedef uint32_t ttl_t; + +typedef uint32_t request_t; +typedef uint16_t client_t; +typedef uint16_t session_t; + +typedef uint32_t length_t; + +typedef uint8_t protocol_version_t; +typedef uint8_t interface_version_t; + +typedef uint8_t byte_t; + +// Addresses +typedef std::array<byte_t, 4> ipv4_address_t; +typedef std::array<byte_t, 16> ipv6_address_t; + +typedef std::string trace_channel_t; + +typedef std::string trace_filter_type_t; + +typedef std::uint16_t pending_subscription_id_t; + +typedef std::uint32_t pending_remote_offer_id_t; + +typedef std::uint32_t pending_security_update_id_t; + +#ifdef _WIN32 + typedef std::uint32_t uid_t; + typedef std::uint32_t gid_t; +#else + typedef ::uid_t uid_t; + typedef ::uid_t gid_t; +#endif + +} // namespace vsomeip + +#endif // VSOMEIP_PRIMITIVE_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/runtime.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/runtime.hpp new file mode 100644 index 00000000000..fda15ec50e0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/runtime.hpp @@ -0,0 +1,216 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_RUNTIME_HPP +#define VSOMEIP_RUNTIME_HPP + +#include <memory> +#include <string> +#include <vector> + +#include "../../compat/vsomeip/export.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { + +class application; +class message; +class payload; + +/** + * + * \defgroup vsomeip + * + * The vsomeip module contains all elements a user applications needs to: + * + * - offer SOME/IP service instances + * - request SOME/IP service instances + * - offer SOME/IP eventgroups + * - subscribe to SOME/IP eventgroups + * - send and receive SOME/IP messages (request/response) + * - implement SOME/IP events and fields + * + * @{ + * + */ + +/** + * + * \brief Singleton class containing all public resource management + * facilities of vsomeip. + * + * The methods of this class shall be used to create instances of all the + * classes needed to facilitate SOME/IP communication. In particular, it is + * the entry point to create instances of the @ref application class that + * contains the main public API of vsomeip. + * + */ +class VSOMEIP_EXPORT runtime { +public: + + static std::string get_property(const std::string &_name); + static void set_property(const std::string &_name, const std::string &_value); + + static std::shared_ptr<runtime> get(); + + virtual ~runtime() { + } + + /** + * + * \brief Creates a vsomeip application object. + * + * An application object manages service offers and requests as well as + * event subscriptions. It allows to register user application functions + * as callbacks that are called on specific events during runtime, e.g + * to react on incoming SOME/IP messages. + * An application object is identified by a unique name that is also used + * in (and therefore has to match) the configuration files of vsomeip. If + * the name is left empty, the application name is taken from the + * environment variable "VSOMEIP_APPLICATION_NAME" + * + * \param _name Name of the application on the system. + * + */ + virtual std::shared_ptr<application> create_application( + const std::string &_name = "") = 0; + + /** + * + * \brief Constructs an empty message object. + * + * The message can then be used to call @application::send to send a + * SOME/IP message. The user application is responsible for setting + * the message type, the service instance and the message payload + * after this call and before calling @application::send. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + */ + virtual std::shared_ptr<message> create_message( + bool _reliable = false) const = 0; + /** + * + * \brief Constructs an empty request message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to REQUEST after the + * call and the request identifier is automatically set during the + * @ref application::send call. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + */ + virtual std::shared_ptr<message> create_request( + bool _reliable = false) const = 0; + + /* + * \brief Constructs an empty response message from a given request + * message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to RESPONSE after the + * call and the request identifier is automatically set from the + * request message. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _request The request message that shall be answered by + * the response message. + * + */ + virtual std::shared_ptr<message> create_response( + const std::shared_ptr<message> &_request) const = 0; + + /** + * + * \brief Creates an empty notification message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to NOTIFICATION after the + * call. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + * Note: Creating notification messages and sending them using + * @ref application::send is possible but not the standard way of sending + * notification with vsomeip. The standard way is calling + * @ref application::offer_event and setting the value using the + * @ref application::notify / @ref application::notify_one methods. + * + */ + virtual std::shared_ptr<message> create_notification( + bool _reliable = false) const = 0; + + /** + * + * \brief Creates an empty payload object. + * + */ + virtual std::shared_ptr<payload> create_payload() const = 0; + + /** + * + * \brief Creates a payload object filled with the given data. + * + * \param _data Bytes to be copied into the payload object. + * \param _size Number of bytes to be copied into the payload object. + * + */ + virtual std::shared_ptr<payload> create_payload( + const byte_t *_data, uint32_t _size) const = 0; + + /** + * + * \brief Creates a payload object filled with the given data. + * + * \param _data Bytes to be copied into the payload object. + * + */ + virtual std::shared_ptr<payload> create_payload( + const std::vector<byte_t> &_data) const = 0; + + /** + * + * \brief Retrieves the application object for the application with the + * given name. + * + * If no such application is found, an empty shared_ptr is returned + * (nullptr). + * + * \param _name Name of the application to be found. + * + */ + virtual std::shared_ptr<application> get_application( + const std::string &_name) const = 0; + + /** + * + * \brief Removes the application object for the application with the + * given name. + * + * If no such application is found, this is a null operation. + * + * \param _name Name of the application to be removed. + * + */ + virtual void remove_application( const std::string &_name) = 0; +}; + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_RUNTIME_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/trace.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/trace.hpp new file mode 100644 index 00000000000..db2054a7242 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/trace.hpp @@ -0,0 +1,218 @@ +// Copyright (C) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_TRACE_HPP_ +#define VSOMEIP_TRACE_HPP_ + +#include <memory> +#include <vector> + +#include "../../compat/vsomeip/constants.hpp" +#include "../../compat/vsomeip/primitive_types.hpp" + +namespace vsomeip { +/** + * \defgroup vsomeip + * + * @{ + */ +namespace trace { + +/** + * \brief Unique identifier for trace filters. + */ +typedef uint32_t filter_id_t; + +/** + * \brief Error value. + */ +extern const filter_id_t FILTER_ID_ERROR; + +/** + * \brief The default channel id "TC". + */ +extern const char *VSOMEIP_TC_DEFAULT_CHANNEL_ID; + +/** + * \brief Filters contain at least one match that specified + * which messages are filtered. + */ +typedef std::tuple<service_t, instance_t, method_t> match_t; + +/** + * \brief Representation of a DLT trace channel. + * + * A trace channel contains one or more filters that specify the + * messages that are forwarded to the trace. + */ +class channel { +public: + virtual ~channel() {}; + + /** + * \brief Get the identifier of the channel. + * + * \return Channel identifier. + */ + virtual std::string get_id() const = 0; + + /** + * \brief Get the name of the channel. + * + * \return Channel name. + */ + virtual std::string get_name() const = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a simple filter containing a single match. + * + * Note: The match is allowed to contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _match The tuple specifying the matching messages. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const match_t &_match, + bool _is_positive = true) = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a filter containing a list of matches to the + * channel. The filter matches if at least on of the + * matches corresponds to a message. + * + * Note: The matches are allowed to contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _matches List of tuples specifying the matching messages. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const std::vector<match_t> &_matches, + bool _is_positive = true) = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a filter containing a matches range to the + * channel. The filter matches if the message identifiers + * lie within the range specified by from and to. Thus, + * the messages service identifier is greater equal than + * the service identifier specified in from and less equal + * than the service identifier specified in to. + * + * Note: from and to must not contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _from Tuples specifying the matching message with + * the smallest identifiers. + * \param _from Tuples specifying the matching message with + * the greatest identifiers. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const match_t &_from, const match_t &_to, + bool _is_positive = true) = 0; + + /** + * \brief Remove a filter from the channel. + * + * Remove the filter with the given filter identifier + * from the channel. + * + * \param _id Filter identifier of the filter that shall + * be removed. + */ + virtual void remove_filter( + filter_id_t _id) = 0; +}; + +/** + * \brief Singleton class to connect to the DLT tracing. + * + * The main configuration class of the DLT tracing. It holds + * the trace channels which determine the messages that are + * forwarded to the trace. + */ +class connector { +public: + /** + * \brief Get access to the connector. + * + * \return Shared pointer to the singleton object. + */ + static std::shared_ptr<connector> get(); + + virtual ~connector() {}; + + /** + * \brief Add a trace channel to the connector. + * + * Creates a trace channel with the given identifier and name + * and adds it to the connector. + * + * \param _id Id of the trace channel. + * \param _name Name of the trace channel + * + * \return Shared pointer to the created trace channel or + * nullptr if the trace channel could not be created because + * another trace channel with the given identifier does + * already exist. + */ + virtual std::shared_ptr<channel> add_channel( + const std::string &_id, + const std::string &_name) = 0; + + /** + * \brief Remove a trace channel from the connector. + * + * Removes the trace channel with the given identifier from + * the connector. + * + * \param _id Identifier of a trace channel. + * + * \return True of the trace channel was removed, False if + * it could not be removed, because it is the default trace + * channel. + */ + virtual bool remove_channel( + const std::string &_id) = 0; + + /** + * \brief Get a trace channel from the connector. + * + * \param _id Identifier of the trace channel to be returned. + * Optional argument that is predefined with the identifier + * of the default trace channel. + * + * \return Shared pointer to the created trace channel or + * nullptr if the trace channel does not exist. + */ + virtual std::shared_ptr<channel> get_channel( + const std::string &_id = VSOMEIP_TC_DEFAULT_CHANNEL_ID) const = 0; +}; + +} // namespace trace + +/** @} */ + +} // namespace vsomeip + +#endif // VSOMEIP_CONSTANTS_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/vsomeip.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/vsomeip.hpp new file mode 100644 index 00000000000..101e136ea7f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/compat/vsomeip/vsomeip.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_VSOMEIP_HPP +#define VSOMEIP_VSOMEIP_HPP + +/** + * \brief The central vsomeip header. Include this to use vsomeip. + */ + +#include "../../compat/vsomeip/application.hpp" +#include "../../compat/vsomeip/constants.hpp" +#include "../../compat/vsomeip/defines.hpp" +#include "../../compat/vsomeip/message.hpp" +#include "../../compat/vsomeip/payload.hpp" +#include "../../compat/vsomeip/runtime.hpp" +#include "../../compat/vsomeip/trace.hpp" + +#endif // VSOMEIP_VSOMEIP_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/application.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/application.hpp new file mode 100644 index 00000000000..b81c90e691b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/application.hpp @@ -0,0 +1,1162 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_APPLICATION_HPP_ +#define VSOMEIP_V3_APPLICATION_HPP_ + +#include <chrono> +#include <memory> +#include <set> +#include <map> +#include <vector> + +#include <vsomeip/deprecated.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/structured_types.hpp> +#include <vsomeip/function_types.hpp> +#include <vsomeip/constants.hpp> +#include <vsomeip/handler.hpp> + +namespace vsomeip_v3 { + +class configuration; +class configuration_public; +class event; +class payload; +struct policy; +class policy_manager; + +/** + * \defgroup vsomeip + * + * @{ + */ + +/** + * + * \brief This class contains the public API of the vsomeip implementation. + * + * Due to its heavy resource footprint, it should exist once per client and can + * be instantiated using the API of @ref runtime. It manages the lifecycle of + * the vsomeip client and allocates all resources needed to communicate. + * + */ +class application { +public: + virtual ~application() {} + + /** + * + * \brief Returns the name of the application as given during creation + * + * The application name is used to identify the application. It is either + * set explicitely when the application object is created or configured by + * the environment variable VSOMEIP_APPLICATION_NAME. + * + * Note: A user application can use several vsomeip application objects in + * parallel. The application names must be set explicitly in this case + * because VSOMEIP_APPLICATION_NAME only allows to specify a single name. + * + * + * \return Application name + * + */ + virtual const std::string & get_name() const = 0; + + /** + * + * \brief Returns the client identifier that was assigned to the + * application object. + * + * Each request sent by and each response sent to the application contain + * the client identifier as part of the request identifier within the + * SOME/IP message header. The client identifier can either be configured + * by the configured as part of the application node within a vsomeip + * configuration file or is automatically set to an unused client + * identifier by vsomeip. If the client identifier is automatically set, + * its high byte will always match the diagnosis address of the device. + * + * \return Client ID of application + * + */ + virtual client_t get_client() const = 0; + + /** + * \brief Get the diagnosis address + * + * \return diagnosis address + */ + virtual diagnosis_t get_diagnosis() const = 0; + + /** + * + * \brief Initializes the application. + * + * The init method must be called first after creating a vsomeip + * application and executes the following steps to initialize it: + * - Loading the configuration from a dynamic module + * - Loading the configuration from a .json file or + * - Loading the configuration from compiled data (not yet available) + * - Determining routing configuration and initialization of the routing + * itself + * - Installing signal handlers + * + */ + virtual bool init() = 0; + + /** + * + * \brief Starts message processing. + * + * This method must be called after init to start message processing. It + * will block until the message processing is terminated using the @ref + * stop method or by receiving signals. It processes messages received + * via the sockets and uses registered callbacks to pass them to the user + * application. + * + */ + virtual void start() = 0; + + /** + * \brief Stops message processing. + * + * This method stops message processing. Thus, @ref start will return + * after a call to stop. + * + */ + virtual void stop() = 0; + + /** + * \brief Process messages / events. + * + * This methods controls the message / event processing from an application + * context. You must not call start / stop if you use this method. + * + * \param _number Number of events/messages that will be processed at + * maximum before returning. + * + */ + virtual void process(int _number = VSOMEIP_ALL) = 0; + + /** + * + * \brief Get the security mode of the application + * + * \return security mode + */ + virtual security_mode_e get_security_mode() const = 0; + + /** + * + * \brief Offers a SOME/IP service instance. + * + * The user application must call this method for each service it offers + * to register it at the vsomeip routing component, which makes the + * service visible to interested clients. Dependent on the configuration + * the service is available internally only or internally and externally. + * To offer a service to the external network, the configuration must + * contain a port for the offered service instance. If no such port + * configuration is provided, the service is not visible outside the + * device. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifier of the offered service instance. + * \param _major Major service version (Default: 0). + * \param _minor Minor service version (Default: 0). + * + */ + virtual void offer_service(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = + DEFAULT_MINOR) = 0; + + /** + * + * \brief Stops offering a SOME/IP service instance. + * + * The user application must call this method to withdraw a service offer. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifier of the offered service instance. + * \param _major Major service version (Default: 0). + * \param _minor Minor service version (Default: 0). + * + */ + virtual void stop_offer_service(service_t _service, instance_t _instance, + major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = + DEFAULT_MINOR) = 0; + + /** + * + * \brief Offers a SOME/IP event or field. + * + * A user application must call this method for each event/field it wants + * to offer. The event is registered at the vsomeip routing component that + * enables other applications to subscribe to the event/field as well as + * to get and set the field value. + * + * \param _service Service identifier of the interface containing the + * event. + * \param _instance Instance identifier of the interface containing the + * event. + * \param _notifier Identifier of the notifier for the offered event. + * \param _eventgroups List of eventgroup identifiers of the eventgroups + * that contain the event. + * \param _type Pure event, selective event or field. + * \param _cycle Cycle time for periodic events + * \param _change_resets_cycle Set to true if a change of the event + * payload shall reset the cycle time for periodically sent events + * \param _update_on_change Set to false if a change of the event should not + * trigger a notification + * \param _epsilon_change_func Function to determine whether two event + * payloads are considered different + * \param _reliability Either RT_UNRELIABLE or RT_RELIABLE. All events + * of the same eventgroup are required to be offered with the same + * reliability. If set to RT_BOTH remote subscriptions are required to + * contain a reliable and unreliable endpoint option to be accepted. + * If set to RT_UNKNOWN the event reliability is determined by the service + * instance's reliability configuration. This parameter has no effect for + * events of local services. + */ + virtual void offer_event(service_t _service, instance_t _instance, + event_t _notifier, const std::set<eventgroup_t> &_eventgroups, + event_type_e _type = event_type_e::ET_EVENT, + std::chrono::milliseconds _cycle =std::chrono::milliseconds::zero(), + bool _change_resets_cycle = false, + bool _update_on_change = true, + const epsilon_change_func_t &_epsilon_change_func = nullptr, + reliability_type_e _reliability = reliability_type_e::RT_UNKNOWN) = 0; + + /** + * + * \brief Stops offering a SOME/IP event or field. + * + * A user application must call this method to withdraw the offer of an + * event or field. + * + * \param _service Service identifier of the interface that contains the + * event + * \param _instance Instance identifier of the interface that contains the + * event + * \param _event Event identifier of the offered event. + * + */ + virtual void stop_offer_event(service_t _service, + instance_t _instance, event_t _event) = 0; + + /** + * + * \brief Registers the application as client of a service instance. + * + * A user application must call this method for each service instance it + * wants to use. The request is stored within the routing component and the + * application is registered as client for the service as soon as the + * service instance becomes available. + * + * \param _service Service identifier of the requested service interface. + * \param _instance Instance identifier of the requested service instance. + * \param _major Major service version (Default: 0xFF). + * \param _minor Minor service version (Default: 0xFFFFFF). + * + */ + virtual void request_service(service_t _service, instance_t _instance, + major_version_t _major = ANY_MAJOR, + minor_version_t _minor = ANY_MINOR) = 0; + + /** + * + * \brief Unregister the application as client of a service instance. + * + * A user application should call this method if it does not request to + * use the service instance any longer. The method unregisters the request + * a the routing component, which removes the service instance from the + * list of requested service instances if the call releases the last + * existing request for the service instance. This is important for + * external service instances, as the SOME/IP Service Discovery can avoid + * to send unnecessary Find messages. + * + * \param _service Service identifier of the offered service interface. + * \param _instance Instance identifier of the offered service instance. + * + */ + virtual void release_service(service_t _service, instance_t _instance) = 0; + + /** + * + * \brief Registers the application as user of an event or field. + * + * A user application must call this method before being able to receive + * event or field data. The method registers the event or field at the + * routing component. + * + * \param _service Service identifier of the interface that contains the + * event. + * \param _instance Instance identifier of the interface that contains the + * event. + * \param _event Event identifier of the event. + * \param _eventgroups List of Eventgroup identifiers of the eventgroups + * that contain the event. + * \param _type Pure event, selective event or field. + * \param _reliability Either RT_UNRELIABLE or RT_RELIABLE. All events + * of the same eventgroup are required to be requested with the same + * reliability. If set to RT_BOTH remote subscriptions are only done if + * the remote service is offered with an unreliable and reliable endpoint + * option. If set to RT_UNKNOWN the event reliability is determined by the + * service instance's reliability configuration. This parameter has no + * effect for events of local services + * + * Note: If a vsomeip application registers to an event or field and other + * vsomeip application shall be enabled to use events/fields from the same + * eventgroup, the application must register all events and fields that + * belong to the eventgroup. Otherwise, neither event type nor reliability + * type are known which might result in missing events. + */ + virtual void request_event(service_t _service, instance_t _instance, + event_t _event, const std::set<eventgroup_t> &_eventgroups, + event_type_e _type = event_type_e::ET_EVENT, + reliability_type_e _reliability = reliability_type_e::RT_UNKNOWN) = 0; + /** + * + * \brief Unregister the application as user of an event or field. + * + * Unregister the application as user of an event or field and completely + * removes the event/field if the application is the last existing user. + * + * \param _service Service identifier of the interface that contains the + * event or field. + * \param _instance Instance identifier of the instance that contains the + * event or field. + * \param _event Event identifier of the event or field. + * . + */ + virtual void release_event(service_t _service, instance_t _instance, + event_t _event) = 0; + + /** + * + * \brief Subscribes to an eventgroup. + * + * A user application must call this function to subscribe to an eventgroup. + * Before calling subscribe it must register all events it interested in by + * calls to @ref request_event. The method additionally allows to specify + * a specific event. If a specific event is specified, all other events of + * the eventgroup are not received by the application. + * + * Note: For external services, providing a specific event does not change + * anything regarding the message routing. The specific event is only used + * to filter incoming events and to determine which initial events must be + * sent. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * \param _major Major version number of the service. + * \param _event All (Default) or a specific event. + * + */ + virtual void subscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major = DEFAULT_MAJOR, + event_t _event = ANY_EVENT) = 0; + + /** + * + * \brief Unsubscribes from an eventgroup. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * + */ + virtual void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup) = 0; + + /** + * + * \brief Retrieve for the availability of a service instance. + * + * If the version is also given, the result will only be true if the + * service instance is available in that specific version. + * + * \param _service Service identifier of the service instance. + * \param _instance Instance identifier of the service instance. + * \param _major Major interface version. Use ANY_MAJOR to ignore the + * major version. + * \param _minor Minor interface version. Use ANY_MINOR to ignore the + * minor version. + * + */ + virtual bool is_available(service_t _service, instance_t _instance, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const = 0; + + typedef std::map<service_t, + std::map<instance_t, + std::map<major_version_t, minor_version_t >>> available_t; + + virtual bool are_available(available_t &_available, + service_t _service = ANY_SERVICE, instance_t _instance = ANY_INSTANCE, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) const = 0; + + /** + * + * \brief Sends a message. + * + * Serializes the specified message object, determines the target and sends + * the message to the target. For requests, the request identifier is + * automatically built from the client identifier and the session + * identifier. + * + * \param _message Message object. + * + */ + virtual void send(std::shared_ptr<message> _message) = 0; + + /** + * + * \brief Fire an event or field notification. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * + */ + virtual void notify(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, + bool _force = false) const = 0; + + /** + * + * \brief Fire an event to a specific client. + * + * The specified event is updated with the specified payload data. + * Dependent on the type of the event, the payload is distributed to all + * notified clients (always for events, only if the payload has changed + * for fields). + * + * Note: Prior to using this method, @ref offer_event has to be called by + * the service provider. + * + * \param _service Service identifier of the service that contains the + * event. + * \param _instance Instance identifier of the service instance that + * holds the event. + * \param _event Event identifier of the event. + * \param _payload Serialized payload of the event. + * \param _client Target client. + * + */ + virtual void notify_one(service_t _service, instance_t _instance, + event_t _event, std::shared_ptr<payload> _payload, client_t _client, + bool _force = false) const = 0; + + /** + * + * \brief Register a state handler with the vsomeip runtime. + * + * The state handler tells if this client is successfully [de]registered + * at the central vsomeip routing component. This is called during the + * @ref start and @ref stop methods of this class to inform the user + * application about the registration state. + * + * \param _handler Handler function to be called on state change. + * + */ + virtual void register_state_handler(const state_handler_t &_handler) = 0; + + /** + * + * \brief Unregister the state handler. + * + */ + virtual void unregister_state_handler() = 0; + + /** + * + * \brief Registers a handler for the specified method or event. + * + * A user application must call this method to register callbacks for + * for messages that match the specified service, instance, method/event + * pattern. It is possible to specify wildcard values for all three + * identifiers arguments. + * + * Notes: + * - Only a single handler can be registered per service, instance, + * method/event combination. + * - A subsequent call will overwrite an existing registration. + * - Handler registrations containing wildcards can be active in parallel + * to handler registrations for specific service, instance, method/event + * combinations. + * + * \param _service Service identifier of the service that contains the + * method or event. Can be set to ANY_SERVICE to register a handler for + * a message independent from a specific service. + * \param _instance Instance identifier of the service instance that + * contains the method or event. Can be set to ANY_INSTANCE to register + * a handler for a message independent from a specific service. + * \param _method Method/Event identifier of the method/event that is + * to be handled. Can be set to ANY_METHOD to register a handler for + * all methods and events. + * \param _handler Callback that will be called if a message arrives + * that matches the specified service, instance and method/event + * parameters. + * + */ + virtual void register_message_handler(service_t _service, + instance_t _instance, method_t _method, + const message_handler_t &_handler) = 0; + /** + * + * \brief Unregisters the message handler for the specified service + * method/event notification. + * + * \param _service Service identifier of the service that contains the + * method or event. Can be set to ANY_SERVICE to unregister a handler for + * a message independent from a specific service. + * \param _instance Instance identifier of the service instance that + * contains the method or event. Can be set to ANY_INSTANCE to unregister + * a handler for a message independent from a specific service. + * \param _method Method/Event identifier of the method/event that is + * to be handled. Can be set to ANY_METHOD to unregister a handler for + * all methods and events. + */ + virtual void unregister_message_handler(service_t _service, + instance_t _instance, method_t _method) = 0; + + /** + * + * \brief Register a callback that is called when service instances + * availability changes. + * + * This method allows for the registration of callbacks that are called + * whenever a service appears or disappears. It is possible to specify + * wildcards for service, instance and/or version. Additionally, the + * version specification is optional and defaults to DEFAULT_MAJOR + * /DEFAULT_MINOR. + * + * \param _service Service identifier of the service instance whose + * availability shall be reported. Can be set to ANY_SERVICE. + * \param _instance Instance identifier of the service instance whose + * availability shall be reported. Can be set to ANY_INSTANCE. + * \param _handler Callback to be called if availability changes. + * \param _major Major service version. The parameter defaults to + * DEFAULT_MAJOR and can be set to ANY_MAJOR. + * \param _minor Minor service version. The parameter defaults to + * DEFAULT_MINOR and can be set to ANY_MINOR. + * + */ + virtual void register_availability_handler(service_t _service, + instance_t _instance, const availability_handler_t &_handler, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) = 0; + + /** + * + * \brief Unregister an availability callback. + * + * \param _service Service identifier of the service instance whose + * availability shall be reported. Can be set to ANY_SERVICE. + * \param _instance Instance identifier of the service instance whose + * availability shall be reported. Can be set to ANY_INSTANCE. + * \param _major Major service version. The parameter defaults to + * DEFAULT_MAJOR and can be set to ANY_MAJOR. + * \param _minor Minor service version. The parameter defaults to + * DEFAULT_MINOR and can be set to ANY_MINOR. * + */ + virtual void unregister_availability_handler(service_t _service, + instance_t _instance, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) = 0; + + /** + * + * \brief Registers a subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value returned by this + * handler decides if the subscription is accepted or not. + * + */ + VSOMEIP_DEPRECATED_UID_GID + virtual void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_t &_handler) = 0; + + /** + * + * \brief Registers an async subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * This method offers the possibility to asynchronously accept/rejects + * subscriptions through a callback. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value passed to the + * callback passed as a parameter to this handler decides if the + * subscription is accepted or not. + * + */ + VSOMEIP_DEPRECATED_UID_GID + virtual void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const async_subscription_handler_t &_handler) = 0; + + /** + * + * \brief Unregister a subscription handler. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * + */ + virtual void unregister_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup) = 0; + + /** + * + * \brief Unregister all registered handlers. + * + */ + virtual void clear_all_handler() = 0; + + /** + * + * \brief This method tells whether or not this application controls the + * message routing. + * + * The application that controls the routing hosts the routing manager + * and (optionally) loads the Service Discovery component. + * + * \return true, if this is the central routing instance, and false + * otherwise + * + */ + virtual bool is_routing() const = 0; + + /** + * \brief Set the current routing state. + * + * The routing state impacts the behavior of the SOME/IP Service Discovery component. It + * can be set to RUNNING, SUSPENDED, RESUMED, SHUTDOWN or UNKNOWN. Applications only need + * to set the routing state if they are responsible for controlling the routing manager. + * In most environments the vsomeip daemon is controlling the routing manager. + * + * \param _routing_state the current routing state + */ + virtual void set_routing_state(routing_state_e _routing_state) = 0; + + /** + * + * \brief Unsubscribes from an eventgroup. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * \param _event Event to unsubscribe (pass ANY_EVENT for all events of the eventgroup) + */ + virtual void unsubscribe(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event) = 0; + + /** + * + * \brief Registers a subscription status listener. + * + * When registered such a handler it will be called for + * every application::subscribe call. + * + * The handler is called whenever a subscription request for an eventgroup + * and/or event was either accepted or rejected. The respective callback is + * called with either OK (0x00) or REJECTED (0x07). + * + * \param _service Service identifier of the service that is subscribed to. + * \param _instance Instance identifier of the service that is subscribed to. + * \param _eventgroup Eventgroup identifier of the eventgroup is subscribed to. + * \param _event Event indentifier of the event is subscribed to. + * \param _handler A subscription status handler which will be called by vSomeIP + * as a follow of application::subscribe. + * \param _is_selective Flag to enable calling the provided handler if the + * subscription is answered with a SUBSCRIBE_NACK. + */ + virtual void register_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event, + subscription_status_handler_t _handler, bool _is_selective = false) = 0; + + /** + * + * \brief Unregisters a subscription status listener. + * + * \param _service Service identifier of the service for which the handler + * should be removed. + * \param _instance Instance identifier of the service for which the handler + * should be removed + * \param _eventgroup Eventgroup identifier of the eventgroup for which the + * should be removed + * \param _event Event identifier of the event for which the handler should + * be removed. + */ + virtual void unregister_subscription_status_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, event_t _event) = 0; + + /** + * + * \brief Returns all registered services / instances on this node in an async callback. + * + * When called with a handler of type offered_services_handler_t, + * all at the routing manager registered services on this node get returned in a vector of + * service / instance pairs depending on the given _offer_type. + * + * \param _offer_type type of offered services to be returned (OT_LOCAL = 0x00, OT_REMOTE = 0x01, OT_ALL = 0x02) + * \param offered_services_handler_t handler which gets called with a vector of service instance pairs that are currently offered + */ + virtual void get_offered_services_async(offer_type_e _offer_type, const offered_services_handler_t &_handler) = 0; + + /** + * + * \brief Sets a handler to be called cyclically for watchdog monitoring. + * + * The handler shall be called in the given interval, but not before start() + * has been called, and not after call to stop() returned. + * + * In case the application is running, i.e. start() succeeded, but the + * handler will not be invoke within the (approximate) interval it may + * be assumed that I/O or internal dispatcher threads are non-functional. + * + * \remark Accuracy of call interval is limited by clock/timer granularity + * or scheduling effects, thus it may underrun or overrun by small + * amount. + * + * \note Only one handler can be active at a time, thus last handler set + * by calling this function will be invoked. + * + * \note To disable calling an active handler, invoke this method again, + * passing nullptr as _handler and/or std::chrono::seconds::zero() + * as _interval. + * + * \param _handler A watchdog handler, pass nullptr to deactivate. + * \param _interval Call interval in seconds, pass std::chrono::seconds::zero() to deactivate. + */ + virtual void set_watchdog_handler(const watchdog_handler_t &_handler, std::chrono::seconds _interval) = 0; + + /** + * \brief Enables or disables calling of registered acceptance + * handlers for given remote info + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _remote IP and port for which SD acceptance handler should be + * called + * \param _path Path which indicates need for offer acceptance + * \param _enable enable or disable calling of offer acceptance handler + */ + virtual void set_sd_acceptance_required(const remote_info_t& _remote, + const std::string& _path, + bool _enable) = 0; + + /** + * \brief Enables or disables calling of registered acceptance + * handlers for given remote info + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _remotes remote infos for which SD acceptance handler should be + * called + * \param _enable enable or disable calling of offer acceptance handler + */ + typedef std::map<remote_info_t, std::string> sd_acceptance_map_type_t; + virtual void set_sd_acceptance_required( + const sd_acceptance_map_type_t& _remotes, bool _enable) = 0; + + /** + * \brief Returns all configured remote info which require calling of + * registered service discovery (SD) acceptance handler + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \return map with known remotes requiring SD acceptance handling + */ + virtual sd_acceptance_map_type_t get_sd_acceptance_required() = 0; + + /** + * \brief Registers a handler which will be called upon reception of + * a remote SD message with the sending ECU's IP address and port as + * parameter + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_sd_acceptance_handler(const sd_acceptance_handler_t &_handler) = 0; + + /** + * \brief Registers a handler which will be called upon detection of a + * reboot of a remote ECU with the remote ECU's IP address as a parameter + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_reboot_notification_handler( + const reboot_notification_handler_t &_handler) = 0; + + /** + * \brief Registers a handler which will be called when the routing reached + * READY state. + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_routing_ready_handler( + const routing_ready_handler_t &_handler) = 0; + + /** + * \brief Registers a handler which will be called when the routing state + * changes. + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_routing_state_handler( + const routing_state_handler_t &_handler) = 0; + + /** + * \brief Update service configuration to offer a local service on the + * network as well + * + * This function is intended to take the necessary information to offer a + * service remotely if it was offered only locally beforehand. + * Precondition: The service must already be offered locally before + * calling this method. + * This function only has an effect if called on an application acting as + * routing manager. + * + * \param _service Service identifier + * \param _instance Instance identifier + * \param _port The port number on which the service should be offered + * \param _reliable Offer via TCP or UDP + * \param _magic_cookies_enabled Flag to enable magic cookies + * \param _offer Offer the service or stop offering it remotely + */ + virtual bool update_service_configuration(service_t _service, + instance_t _instance, + std::uint16_t _port, + bool _reliable, + bool _magic_cookies_enabled, + bool _offer) = 0; + + /** + * \brief Update security configuration of routing manager and all local clients + * The given handler gets called with "SU_SUCCESS" if the policy for UID + * and GID was updated or added successfully. If not all clients did confirm + * the update, SU_TIMEOUT is set. + * + * \param _uid UID of the policy + * \param _gid GID of the policy + * \param _policy The security policy to apply + * \param _payload serialized security policy object + * \param _handler handler which gets called after all clients have + * confirmed the policy update + */ + virtual void update_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + std::shared_ptr<policy> _policy, + std::shared_ptr<payload> _payload, + const security_update_handler_t &_handler) = 0; + + /** + * \brief Remove a security configuration for routing manager and all local clients + * The given handler gets called with "SU_SUCCESS" if the policy for UID + * and GID was removed successfully. SU_UNKNOWN_USER_ID is set if the + * UID and GID was not found. If not all clients did confirm the removal, + * SU_TIMEOUT is set. + * + * \param _uid UID of the policy to remove + * \param _gid GID of the policy to remove + * \param _handler handler which gets called after all clients have + * confirmed the policy removal + */ + virtual void remove_security_policy_configuration(uint32_t _uid, + uint32_t _gid, + const security_update_handler_t &_handler) = 0; + + /** + * + * \brief Registers a subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value returned by this + * handler decides if the subscription is accepted or not. + * + */ + VSOMEIP_DEPRECATED_UID_GID + virtual void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_ext_t &_handler) = 0; + + /** + * + * \brief Registers an async subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * This method offers the possibility to asynchronously accept/rejects + * subscriptions through a callback. + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value passed to the + * callback passed as a parameter to this handler decides if the + * subscription is accepted or not. + * + */ + VSOMEIP_DEPRECATED_UID_GID + virtual void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + const async_subscription_handler_ext_t &_handler) = 0; + + + /** + * + * \brief Subscribes to an eventgroup. + * + * A user application must call this function to subscribe to an eventgroup. + * Before calling subscribe it must register all events it interested in by + * calls to @ref request_event. The method additionally allows to specify + * a specific event. If a specific event is specified, all other events of + * the eventgroup are not received by the application. + * + * Note: For external services, providing a specific event does not change + * anything regarding the message routing. The specific event is only used + * to filter incoming events and to determine which initial events must be + * sent. + * + * \param _service Service identifier of the service that contains the + * eventgroup. + * \param _instance Instance identifier of the service that contains the + * eventgroup. + * \param _eventgroup Eventgroup identifier of the eventgroup. + * \param _major Major version number of the service. + * \param _event All (Default) or a specific event. + * \param _filter Filter configuration to decide whether or not an + * incoming event will be forwarded to the application. + */ + virtual void subscribe_with_debounce(service_t _service, instance_t _instance, + eventgroup_t _eventgroup, major_version_t _major, + event_t _event, const debounce_filter_t &_filter) = 0; + + /** + * \brief Registers a handler which will be called upon reception of + * a remote VSOMEIP/SD message with the sending ECU's IP address and port as + * parameter + * + * This method has only an effect when called on the application acting as + * routing manager + * + * \param _handler The handler to be called + */ + virtual void register_message_acceptance_handler(const message_acceptance_handler_t &_handler) = 0; + + /** + * \brief Get the configuration additional data of an application plugin + * + * \return The configuration additional data of an application plugin + */ + virtual std::map<std::string, std::string> get_additional_data( + const std::string &_plugin_name) = 0; + + + /** + * + * \brief Register a callback that is called when service instances + * availability (state) changes. + * + * This method allows for the registration of callbacks that are called + * whenever a service appears or disappears. It is possible to specify + * wildcards for service, instance and/or version. Additionally, the + * version specification is optional and defaults to DEFAULT_MAJOR + * /DEFAULT_MINOR. + * + * \param _service Service identifier of the service instance whose + * availability shall be reported. Can be set to ANY_SERVICE. + * \param _instance Instance identifier of the service instance whose + * availability shall be reported. Can be set to ANY_INSTANCE. + * \param _handler Callback to be called if availability (state) changes. + * \param _major Major service version. The parameter defaults to + * DEFAULT_MAJOR and can be set to ANY_MAJOR. + * \param _minor Minor service version. The parameter defaults to + * DEFAULT_MINOR and can be set to ANY_MINOR. + * + */ + virtual void register_availability_handler(service_t _service, + instance_t _instance, const availability_state_handler_t &_handler, + major_version_t _major = ANY_MAJOR, minor_version_t _minor = ANY_MINOR) = 0; + + /** + * + * \brief Registers a subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * (vsomeip_sec_client_t-aware) + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value returned by this + * handler decides if the subscription is accepted or not. + * + */ + virtual void register_subscription_handler(service_t _service, + instance_t _instance, eventgroup_t _eventgroup, + const subscription_handler_sec_t &_handler) = 0; + + /** + * + * \brief Registers an async subscription handler. + * + * A subscription handler is called whenever the subscription state of an + * eventgroup changes. The callback is called with the client identifier + * and a boolean that indicates whether the client subscribed or + * unsubscribed. + * This method offers the possibility to asynchronously accept/rejects + * subscriptions through a callback. + * (vsomeip_sec_client_t-aware) + * + * \param _service Service identifier of service instance whose + * subscription state is to be monitored. + * \param _instance Instance identifier of service instance whose + * subscription state is to be monitored. + * \param _eventgroup Eventgroup identifier of eventgroup whose + * subscription state is to be monitored. + * \param _handler Callback that shall be called. The value passed to the + * callback passed as a parameter to this handler decides if the + * subscription is accepted or not. + * + */ + virtual void register_async_subscription_handler( + service_t _service, instance_t _instance, eventgroup_t _eventgroup, + async_subscription_handler_sec_t _handler) = 0; + + /** + * + * \brief Registers a handler for the specified method or event. + * + * A user application must call this method to register callbacks for + * for messages that match the specified service, instance, method/event + * pattern. It is possible to specify wildcard values for all three + * identifiers arguments. + * + * Notes: + * - Only a single handler can be registered per service, instance, + * method/event combination. + * - A subsequent call will overwrite an existing registration. + * - Handler registrations containing wildcards can be active in parallel + * to handler registrations for specific service, instance, method/event + * combinations. + * + * \param _service Service identifier of the service that contains the + * method or event. Can be set to ANY_SERVICE to register a handler for + * a message independent from a specific service. + * \param _instance Instance identifier of the service instance that + * contains the method or event. Can be set to ANY_INSTANCE to register + * a handler for a message independent from a specific service. + * \param _method Method/Event identifier of the method/event that is + * to be handled. Can be set to ANY_METHOD to register a handler for + * all methods and events. + * \param _handler Callback that will be called if a message arrives + * that matches the specified service, instance and method/event + * parameters. + * \param _type Replace, append to or prepend to the current handler (if + * any). + */ + virtual void register_message_handler_ext(service_t _service, + instance_t _instance, method_t _method, + const message_handler_t &_handler, + handler_registration_type_e _type) = 0; + + /** + * \brief Get the configuration + * + * \return configuration shared pointer + */ + virtual std::shared_ptr<configuration> get_configuration() const = 0; + + /** + * \brief Get the policy_manager + * + * \return policy_manager shared pointer + */ + virtual std::shared_ptr<policy_manager> get_policy_manager() const = 0; +}; + +/** @} */ + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_APPLICATION_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/constants.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/constants.hpp new file mode 100644 index 00000000000..2519b57fe9a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/constants.hpp @@ -0,0 +1,67 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_CONSTANTS_HPP_ +#define VSOMEIP_V3_CONSTANTS_HPP_ + +#include <string> + +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> + +namespace vsomeip_v3 { + +inline constexpr major_version_t DEFAULT_MAJOR = 0x00; +inline constexpr minor_version_t DEFAULT_MINOR = 0x00000000; +inline constexpr ttl_t DEFAULT_TTL = 0xFFFFFF; // "until next reboot" + +const std::string DEFAULT_MULTICAST = "224.0.0.0"; +inline constexpr uint16_t DEFAULT_PORT = 30500; +inline constexpr uint16_t ILLEGAL_PORT = 0xFFFF; +inline constexpr uint16_t ANY_PORT = 0; + +inline constexpr uint16_t NO_TRACE_FILTER_EXPRESSION = 0x0000; + +inline constexpr service_t ANY_SERVICE = 0xFFFF; +inline constexpr instance_t ANY_INSTANCE = 0xFFFF; +inline constexpr eventgroup_t ANY_EVENTGROUP = 0xFFFF; +inline constexpr method_t ANY_METHOD = 0xFFFF; +inline constexpr major_version_t ANY_MAJOR = 0xFF; +inline constexpr minor_version_t ANY_MINOR = 0xFFFFFFFF; + +inline constexpr eventgroup_t DEFAULT_EVENTGROUP = 0x0001; + +inline constexpr client_t ILLEGAL_CLIENT = 0x0000; +inline constexpr method_t INVALID_METHOD = 0x0000; + +inline constexpr byte_t MAGIC_COOKIE_CLIENT_MESSAGE = 0x00; +inline constexpr byte_t MAGIC_COOKIE_SERVICE_MESSAGE = 0x80; +inline constexpr length_t MAGIC_COOKIE_SIZE = 0x00000008; +inline constexpr request_t MAGIC_COOKIE_REQUEST = 0xDEADBEEF; +inline constexpr client_t MAGIC_COOKIE_CLIENT = 0xDEAD; +inline constexpr protocol_version_t MAGIC_COOKIE_PROTOCOL_VERSION = 0x01; +inline constexpr interface_version_t MAGIC_COOKIE_INTERFACE_VERSION = 0x01; +inline constexpr message_type_e MAGIC_COOKIE_CLIENT_MESSAGE_TYPE = + message_type_e::MT_REQUEST_NO_RETURN; +inline constexpr message_type_e MAGIC_COOKIE_SERVICE_MESSAGE_TYPE = + message_type_e::MT_NOTIFICATION; +inline constexpr return_code_e MAGIC_COOKIE_RETURN_CODE = return_code_e::E_OK; + +inline constexpr byte_t CLIENT_COOKIE[] = { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x01, 0x01, 0x00 }; + +inline constexpr byte_t SERVICE_COOKIE[] = { 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x01, 0x02, 0x00 }; + +inline constexpr event_t ANY_EVENT = 0xFFFF; +inline constexpr client_t ANY_CLIENT = 0xFFFF; + +inline constexpr int VSOMEIP_ALL = -1; + +inline constexpr pending_security_update_id_t DEFAULT_SECURITY_UPDATE_ID = 0x0; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONSTANTS_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/defines.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/defines.hpp new file mode 100644 index 00000000000..6485380f0f8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/defines.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_DEFINES_HPP_ +#define VSOMEIP_V3_DEFINES_HPP_ + +#include <cstddef> +#include <cstdint> + +constexpr std::uint8_t VSOMEIP_PROTOCOL_VERSION = 0x1; + +// 0 = unlimited, if not specified otherwise via configuration file +constexpr std::size_t VSOMEIP_MAX_LOCAL_MESSAGE_SIZE = 0; +// 0 = unlimited, if not specified otherwise via configuration file +constexpr std::size_t VSOMEIP_MAX_TCP_MESSAGE_SIZE = 0; +constexpr std::size_t VSOMEIP_MAX_UDP_MESSAGE_SIZE = 1416; + +constexpr std::size_t VSOMEIP_PACKET_SIZE = VSOMEIP_MAX_UDP_MESSAGE_SIZE; + +constexpr std::size_t VSOMEIP_SOMEIP_MAGIC_COOKIE_SIZE = 8; +constexpr std::uint32_t VSOMEIP_SOMEIP_HEADER_SIZE = 8; +constexpr std::uint32_t VSOMEIP_FULL_HEADER_SIZE = 16; + +constexpr std::size_t VSOMEIP_SERVICE_POS_MIN = 0; +constexpr std::size_t VSOMEIP_SERVICE_POS_MAX = 1; +constexpr std::size_t VSOMEIP_METHOD_POS_MIN = 2; +constexpr std::size_t VSOMEIP_METHOD_POS_MAX = 3; +constexpr std::size_t VSOMEIP_EVENT_POS_MIN = 2; +constexpr std::size_t VSOMEIP_EVENT_POS_MAX = 3; +constexpr std::size_t VSOMEIP_LENGTH_POS_MIN = 4; +constexpr std::size_t VSOMEIP_LENGTH_POS_MAX = 7; +constexpr std::size_t VSOMEIP_CLIENT_POS_MIN = 8; +constexpr std::size_t VSOMEIP_CLIENT_POS_MAX = 9; +constexpr std::size_t VSOMEIP_SESSION_POS_MIN = 10; +constexpr std::size_t VSOMEIP_SESSION_POS_MAX = 11; +constexpr std::size_t VSOMEIP_PROTOCOL_VERSION_POS = 12; +constexpr std::size_t VSOMEIP_INTERFACE_VERSION_POS = 13; +constexpr std::size_t VSOMEIP_MESSAGE_TYPE_POS = 14; +constexpr std::size_t VSOMEIP_RETURN_CODE_POS = 15; +constexpr std::size_t VSOMEIP_PAYLOAD_POS = 16; + +#endif // VSOMEIP_V3_DEFINES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/deprecated.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/deprecated.hpp new file mode 100644 index 00000000000..9ba02357343 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/deprecated.hpp @@ -0,0 +1,10 @@ +#ifndef VSOMEIP_V3_DEPRECATED_HPP_ +#define VSOMEIP_V3_DEPRECATED_HPP_ + +#ifdef VSOMEIP_INTERNAL_SUPPRESS_DEPRECATED +#define VSOMEIP_DEPRECATED_UID_GID +#else +#define VSOMEIP_DEPRECATED_UID_GID [[deprecated("Use vsomeip_sec_client_t-aware functions and types instead.")]] +#endif + +#endif // VSOMEIP_V3_DEPRECATED_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/enumeration_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/enumeration_types.hpp new file mode 100644 index 00000000000..b56690de35e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/enumeration_types.hpp @@ -0,0 +1,112 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ENUMERATION_TYPES_HPP_ +#define VSOMEIP_V3_ENUMERATION_TYPES_HPP_ + +#include <cstdint> + +namespace vsomeip_v3 { + +enum class state_type_e : uint8_t { + ST_REGISTERED = 0x0, + ST_DEREGISTERED = 0x1 +}; + +// SIP_RPC_684 +enum class message_type_e : uint8_t { + MT_REQUEST = 0x00, + MT_REQUEST_NO_RETURN = 0x01, + MT_NOTIFICATION = 0x02, + MT_REQUEST_ACK = 0x40, + MT_REQUEST_NO_RETURN_ACK = 0x41, + MT_NOTIFICATION_ACK = 0x42, + MT_RESPONSE = 0x80, + MT_ERROR = 0x81, + MT_RESPONSE_ACK = 0xC0, + MT_ERROR_ACK = 0xC1, + MT_UNKNOWN = 0xFF +}; + +// SIP_RPC_371 +enum class return_code_e : uint8_t { + E_OK = 0x00, + E_NOT_OK = 0x01, + E_UNKNOWN_SERVICE = 0x02, + E_UNKNOWN_METHOD = 0x03, + E_NOT_READY = 0x04, + E_NOT_REACHABLE = 0x05, + E_TIMEOUT = 0x06, + E_WRONG_PROTOCOL_VERSION = 0x07, + E_WRONG_INTERFACE_VERSION = 0x08, + E_MALFORMED_MESSAGE = 0x09, + E_WRONG_MESSAGE_TYPE = 0x0A, + E_UNKNOWN = 0xFF +}; + +enum class routing_state_e : uint8_t { + RS_RUNNING = 0x00, + RS_SUSPENDED = 0x01, + RS_RESUMED = 0x02, + RS_SHUTDOWN = 0x03, + RS_DIAGNOSIS = 0x04, + RS_UNKNOWN = 0xFF +}; + +enum class offer_type_e : uint8_t { + OT_LOCAL = 0x00, + OT_REMOTE = 0x01, + OT_ALL = 0x02, +}; + +enum class event_type_e : uint8_t { + ET_EVENT = 0x00, + ET_SELECTIVE_EVENT = 0x01, + ET_FIELD = 0x02, + ET_UNKNOWN = 0xFF +}; + +enum class security_mode_e : uint8_t { + SM_OFF = 0x00, + SM_ON = 0x01, + SM_AUDIT = 0x02 +}; + +enum class security_update_state_e : uint8_t { + SU_SUCCESS = 0x00, + SU_NOT_ALLOWED = 0x01, + SU_UNKNOWN_USER_ID = 0x02, + SU_INVALID_FORMAT = 0x03 +}; + +enum class reliability_type_e : uint8_t { + RT_RELIABLE = 0x01, + RT_UNRELIABLE = 0x02, + RT_BOTH = 0x3, // RT_RELIABLE | RT_UNRELIABLE + RT_UNKNOWN = 0xFF +}; + +enum class availability_state_e : uint8_t { + AS_UNAVAILABLE = 0x00, // unseen + AS_OFFERED = 0x01, // seen, but not requested/not yet usable + AS_AVAILABLE = 0x02, // seen and usable + AS_UNKNOWN = 0xFF +}; + +enum class handler_registration_type_e : uint8_t { + HRT_REPLACE = 0x00, + HRT_PREPEND = 0x01, + HRT_APPEND = 0x02, + HRT_UNKNOWN = 0xFF +}; + +enum class endianess_e { + be, // big-endian + le // little-endian +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ENUMERATION_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/error.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/error.hpp new file mode 100644 index 00000000000..ecbf591a700 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/error.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_ERROR_HPP_ +#define VSOMEIP_V3_ERROR_HPP_ + +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +enum class error_code_e : uint8_t { + CONFIGURATION_MISSING, + PORT_CONFIGURATION_MISSING, + CLIENT_ENDPOINT_CREATION_FAILED, + SERVER_ENDPOINT_CREATION_FAILED, + SERVICE_PROPERTY_MISMATCH +}; + +extern const char *ERROR_INFO[]; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_ERROR_HPP_ + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/export.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/export.hpp new file mode 100644 index 00000000000..5f460eb03f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/export.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_EXPORT_HPP_ +#define VSOMEIP_V3_EXPORT_HPP_ + +#if _WIN32 + #define VSOMEIP_EXPORT __declspec(dllexport) + #define VSOMEIP_EXPORT_CLASS_EXPLICIT + + #if VSOMEIP_DLL_COMPILATION + #define VSOMEIP_IMPORT_EXPORT __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT __declspec(dllimport) + #endif + + #if VSOMEIP_DLL_COMPILATION_CONFIG + #define VSOMEIP_IMPORT_EXPORT_CONFIG __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT_CONFIG __declspec(dllimport) + #endif +#else + #define VSOMEIP_EXPORT + #define VSOMEIP_IMPORT_EXPORT + #define VSOMEIP_IMPORT_EXPORT_CONFIG +#endif + +#endif // VSOMEIP_V3_EXPORT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/function_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/function_types.hpp new file mode 100644 index 00000000000..61030256a4a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/function_types.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_FUNCTION_TYPES_HPP_ +#define VSOMEIP_V3_FUNCTION_TYPES_HPP_ + +#include <functional> +#include <memory> + +namespace vsomeip_v3 { + +class payload; + +typedef std::function< + bool (const std::shared_ptr<payload> &, + const std::shared_ptr<payload> &) > epsilon_change_func_t; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_FUNCTION_TYPES_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/handler.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/handler.hpp new file mode 100644 index 00000000000..f95ed7b0df5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/handler.hpp @@ -0,0 +1,110 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_HANDLER_HPP_ +#define VSOMEIP_V3_HANDLER_HPP_ + +#include <functional> +#include <memory> +#include <tuple> + +#include <vsomeip/deprecated.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/vsomeip_sec.h> + +namespace vsomeip_v3 { + +class message; + +typedef std::function< void (state_type_e) > state_handler_t; +typedef std::function< void (const std::shared_ptr< message > &) > message_handler_t; +typedef std::function< void (service_t, instance_t, bool) > availability_handler_t; +typedef std::function< void (service_t, instance_t, availability_state_e) > availability_state_handler_t; +VSOMEIP_DEPRECATED_UID_GID typedef std::function< bool (client_t, uid_t, gid_t, bool) > subscription_handler_t; +VSOMEIP_DEPRECATED_UID_GID typedef std::function< bool (client_t, uid_t, gid_t, const std::string &, bool) > subscription_handler_ext_t; +typedef std::function< void (const uint16_t) > error_handler_t; +typedef std::function< void (const service_t, const instance_t, const eventgroup_t, + const event_t, const uint16_t) > subscription_status_handler_t; +VSOMEIP_DEPRECATED_UID_GID typedef std::function< void (client_t, uid_t, gid_t, bool, + std::function< void (const bool) > )> async_subscription_handler_t; +VSOMEIP_DEPRECATED_UID_GID typedef std::function< void (client_t, uid_t, gid_t, const std::string &, bool, + std::function< void (const bool) > )> async_subscription_handler_ext_t; + +typedef std::function< void (const std::vector<std::pair<service_t, instance_t>> &_services) > offered_services_handler_t; +typedef std::function< void () > watchdog_handler_t; + +/* + * vsomeip_sec_client_t-aware subscription handlers + */ +using subscription_handler_sec_t = std::function<bool(client_t, const vsomeip_sec_client_t*, const std::string&, bool)>; +using async_subscription_handler_sec_t = std::function<void(client_t, const vsomeip_sec_client_t*, const std::string&, bool, std::function<void(bool)>)>; + +struct ip_address_t { + union { + ipv4_address_t v4_; + ipv6_address_t v6_; + } address_; + bool is_v4_; + + bool operator<(const ip_address_t& _other) const { + if (is_v4_ && _other.is_v4_) { + return address_.v4_ < _other.address_.v4_; + } else if (!is_v4_ && !_other.is_v4_) { + return address_.v6_ < _other.address_.v6_; + } else if (is_v4_ && !_other.is_v4_) { + return true; + } else { + return false; + } + } + + bool operator==(const ip_address_t& _other) const { + if (is_v4_ && _other.is_v4_) { + return address_.v4_ == _other.address_.v4_; + } else if (!is_v4_ && !_other.is_v4_) { + return address_.v6_ == _other.address_.v6_; + } else { + return false; + } + } + + bool operator!=(const ip_address_t& _other) const { + return !(*this == _other); + } + +}; + +struct remote_info_t { + ip_address_t ip_; + std::uint16_t first_; + std::uint16_t last_; + bool is_range_; + bool is_reliable_; + + bool operator<(const remote_info_t& _other) const { + return std::tie(ip_, first_, last_, is_range_, is_reliable_) < + std::tie(_other.ip_, _other.first_, _other.last_, + _other.is_range_, _other.is_reliable_); + } +}; + +struct message_acceptance_t { + std::uint32_t remote_address_; + std::uint16_t local_port_; + bool is_local_; + service_t service_; + instance_t instance_; +}; + +typedef std::function<bool(const remote_info_t&)> sd_acceptance_handler_t; +typedef std::function<void(const ip_address_t&)> reboot_notification_handler_t; +typedef std::function<void()> routing_ready_handler_t; +typedef std::function<void(routing_state_e)> routing_state_handler_t; +typedef std::function<void(security_update_state_e)> security_update_handler_t; +typedef std::function<bool(const message_acceptance_t&)> message_acceptance_handler_t; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_HANDLER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/deserializable.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/deserializable.hpp new file mode 100644 index 00000000000..b2a549ec419 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/deserializable.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_DESERIALIZABLE_HPP_ +#define VSOMEIP_V3_DESERIALIZABLE_HPP_ + +#include <vsomeip/export.hpp> + +namespace vsomeip_v3 { + +class deserializer; + +class deserializable { +public: + VSOMEIP_EXPORT virtual ~deserializable() { + } + VSOMEIP_EXPORT virtual bool deserialize(deserializer *_from) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERIALIZABLE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/logger.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/logger.hpp new file mode 100644 index 00000000000..4d1f4b64fdf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/logger.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_LOGGER_HPP_ +#define VSOMEIP_V3_LOGGER_HPP_ + +#include <chrono> +#include <cstdint> +#include <mutex> +#include <ostream> +#include <sstream> +#include <streambuf> + +#include <vsomeip/export.hpp> + +namespace vsomeip_v3 { +namespace logger { + +enum class VSOMEIP_IMPORT_EXPORT level_e : std::uint8_t { + LL_NONE = 0, + LL_FATAL = 1, + LL_ERROR = 2, + LL_WARNING = 3, + LL_INFO = 4, + LL_DEBUG = 5, + LL_VERBOSE = 6 +}; + +class message + : public std::ostream { + +public: + VSOMEIP_IMPORT_EXPORT message(level_e _level); + VSOMEIP_IMPORT_EXPORT ~message(); + +private: + class buffer : public std::streambuf { + public: + int_type overflow(int_type); + std::streamsize xsputn(const char *, std::streamsize); + + std::stringstream data_; + }; + + std::chrono::system_clock::time_point when_; + buffer buffer_; + level_e level_; + static std::mutex mutex__; +}; + +} // namespace logger +} // namespace vsomeip_v3 + +#define VSOMEIP_FATAL vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_FATAL) +#define VSOMEIP_ERROR vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_ERROR) +#define VSOMEIP_WARNING vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_WARNING) +#define VSOMEIP_INFO vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_INFO) +#define VSOMEIP_DEBUG vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_DEBUG) +#define VSOMEIP_TRACE vsomeip_v3::logger::message(vsomeip_v3::logger::level_e::LL_VERBOSE) + +#define VSOMEIP_LOG_DEFAULT_APPLICATION_ID "VSIP" +#define VSOMEIP_LOG_DEFAULT_APPLICATION_NAME "vSomeIP application|SysInfra|IPC" + +#endif // VSOMEIP_V3_LOGGER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/plugin_manager.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/plugin_manager.hpp new file mode 100644 index 00000000000..a8b05b22743 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/plugin_manager.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PLUGIN_MANAGER_HPP +#define VSOMEIP_V3_PLUGIN_MANAGER_HPP + +#include <memory> +#include <string> + +#include <vsomeip/export.hpp> +#include <vsomeip/plugin.hpp> + +namespace vsomeip_v3 { + +class plugin_manager { +public: + VSOMEIP_EXPORT virtual ~plugin_manager() {}; + VSOMEIP_EXPORT static std::shared_ptr<plugin_manager> get(); + VSOMEIP_EXPORT virtual void load_plugins() = 0; + VSOMEIP_EXPORT virtual std::shared_ptr<plugin> get_plugin(plugin_type_e _type, const std::string &_name) = 0; + VSOMEIP_EXPORT virtual void * load_library(const std::string &_path) = 0; + VSOMEIP_EXPORT virtual void * load_symbol(void * _handle, const std::string &_symbol) = 0; + VSOMEIP_EXPORT virtual void unload_library(void * _handle) = 0; + VSOMEIP_EXPORT virtual bool unload_plugin(plugin_type_e _type) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PLUGIN_MANAGER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/policy_manager.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/policy_manager.hpp new file mode 100644 index 00000000000..5be22f3e179 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/policy_manager.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_POLICY_MANAGER_HPP_ +#define VSOMEIP_V3_POLICY_MANAGER_HPP_ + + +#include <memory> + +#include <vsomeip/deprecated.hpp> +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +struct policy; + +class VSOMEIP_IMPORT_EXPORT policy_manager { +public: + virtual ~policy_manager() {} + virtual std::shared_ptr<policy> create_policy() const = 0; + virtual void print_policy(const std::shared_ptr<policy> &_policy) const = 0; + + virtual bool parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size, + uid_t &_uid, gid_t &_gid) const = 0; + virtual bool parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size, + uid_t &_uid, gid_t &_gid, + const std::shared_ptr<policy> &_policy) const = 0; + + virtual bool is_policy_update_allowed(uid_t _uid, std::shared_ptr<policy> &_policy) const = 0; + virtual bool is_policy_removal_allowed(uid_t _uid) const = 0; +}; + +} // namespace vsomeip_v3 + + +#endif // VSOMEIP_V3_POLICY_MANAGER_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/serializable.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/serializable.hpp new file mode 100644 index 00000000000..8101e522c15 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/internal/serializable.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SERIALIZABLE_HPP_ +#define VSOMEIP_V3_SERIALIZABLE_HPP_ + +#include <vsomeip/export.hpp> + +namespace vsomeip_v3 { + +class serializer; + +/** + * Abstract base class for element that can be serialized. + */ +class serializable { +public: + VSOMEIP_EXPORT virtual ~serializable() {} + + /** + * \brief serialize the content of the object + */ + VSOMEIP_EXPORT virtual bool serialize(serializer *_to) const = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_SERIALIZABLE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message.hpp new file mode 100644 index 00000000000..e7e0b0dea53 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_MESSAGE_HPP_ +#define VSOMEIP_V3_MESSAGE_HPP_ + +#include <memory> + +#include <vsomeip/deprecated.hpp> +#include <vsomeip/message_base.hpp> +#include <vsomeip/vsomeip_sec.h> + +namespace vsomeip_v3 { + +class payload; + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * \brief Implements regular SOME/IP messages. + * + * This class extends @ref message_base by an unstructured payload. Except + * SOME/IP Service Discovery messages, all SOME/IP messages within vsomeip + * are represented by message objects. + */ + +class message: virtual public message_base { +public: + virtual ~message() {} + + /** + * \brief Returns a pointer to the message payload. + */ + virtual std::shared_ptr<payload> get_payload() const = 0; + + /** + * \brief Set the message payload. + */ + virtual void set_payload(std::shared_ptr<payload> _payload) = 0; + + /** + * \brief Get e2e protection check result. + */ + VSOMEIP_EXPORT virtual uint8_t get_check_result() const = 0; + + /** + * \brief Set e2e protection check result. + */ + VSOMEIP_EXPORT virtual void set_check_result(uint8_t _check_result) = 0; + + /** + * \brief Return whether or not the CRC value received is valid. + */ + VSOMEIP_EXPORT virtual bool is_valid_crc() const = 0; + + /** + * \brief Return uid of the message sender. + */ + VSOMEIP_DEPRECATED_UID_GID VSOMEIP_EXPORT virtual uid_t get_uid() const = 0; + + /** + * \brief Return gid of the message sender. + */ + VSOMEIP_DEPRECATED_UID_GID VSOMEIP_EXPORT virtual gid_t get_gid() const = 0; + + /** + * \brief Return environment (hostname) of the message sender. + */ + VSOMEIP_EXPORT virtual std::string get_env() const = 0; + + /** + * \brief Return security client of the message sender. + */ + VSOMEIP_EXPORT virtual vsomeip_sec_client_t get_sec_client() const = 0; +}; + +/** @} */ + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_MESSAGE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message_base.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message_base.hpp new file mode 100644 index 00000000000..624a160275f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/message_base.hpp @@ -0,0 +1,200 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_MESSAGE_BASE_HPP_ +#define VSOMEIP_V3_MESSAGE_BASE_HPP_ + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/enumeration_types.hpp> + +#include <vsomeip/internal/deserializable.hpp> +#include <vsomeip/internal/serializable.hpp> + +namespace vsomeip_v3 { + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * \brief Base class to implement SOME/IP messages. + * + * This class implements the SOME/IP message header and connects to the + * serialzing/deserializing functionalities. The class is inherited by + * the message classes within ::vsomeip and vsomeip::sd that add the + * payload representations for regular and Service Discovery messages. + */ +class message_base + : public serializable, + public deserializable { +public: + VSOMEIP_EXPORT virtual ~message_base() {}; + + /** + * \brief Returns the message identifier. + * + * The method returns the message identifier that consists of + * service identifier and method identifier. + */ + VSOMEIP_EXPORT virtual message_t get_message() const = 0; + /** + * \brief Set the message identifier. + * + * The methods sets service identifier and method identifier in + * a single call. + * + * \param _message The new message identifier. + */ + VSOMEIP_EXPORT virtual void set_message(message_t _message) = 0; + + /** + * \brief Returns the service identifier from the message header. + */ + VSOMEIP_EXPORT virtual service_t get_service() const = 0; + + /** + * \brief Set the service identifier in the message header. + */ + VSOMEIP_EXPORT virtual void set_service(service_t _service) = 0; + + /** + * \brief Returns the instance identifier. + * + * The instance identifier is _not_ part of the SOME/IP header. It is + * either derived from the incoming message (local) or from the port + * that was used to send a message (external). + */ + VSOMEIP_EXPORT virtual instance_t get_instance() const = 0; + + /** + * \brief Set the instance identifier in the message header. + * + * To address the correct service instance, vsomeip uses the instance + * identifier. For external services it is mapped to a IP address and port + * combination before the message is sent. For internal messages is + * transferred as additional data appended to the SOME/IP messages. + * Therefore, before sending a message, a user application must set the + * instance identifier. + */ + VSOMEIP_EXPORT virtual void set_instance(instance_t _instance) = 0; + + /** + * \brief Get the method/event identifier from the message header. + */ + VSOMEIP_EXPORT virtual method_t get_method() const = 0; + + /** + * \brief Set the method/event identifier in the message header. + */ + VSOMEIP_EXPORT virtual void set_method(method_t _method) = 0; + + /** + * \brief Get the payload length from the message header. + */ + VSOMEIP_EXPORT virtual length_t get_length() const = 0; + + /** + * \brief Get the request identifier from the message header. + * + * The request identifier consists of the client identifier and the + * session identifier. As it does really make sense to set it as + * a whole, setting is not supported. + */ + VSOMEIP_EXPORT virtual request_t get_request() const = 0; + + /** + * \brief Get the client identifier in the message header. + */ + VSOMEIP_EXPORT virtual client_t get_client() const = 0; + + /** + * \brief Set the client identifier in the message header. + * + * For requests this is automatically done by @ref application::send. + * For notications this is not needed. + */ + VSOMEIP_EXPORT virtual void set_client(client_t _client) = 0; + + /** + * \brief Get the session identifier from the message header. + */ + VSOMEIP_EXPORT virtual session_t get_session() const = 0; + + /** + * \brief Set the session identifier in the message header. + * + * For requests this is automatically done by @ref application::send + * For notifications it is not needed to set the session identifier. + */ + VSOMEIP_EXPORT virtual void set_session(session_t _session) = 0; + + /** + * \brief Get the protocol version from the message header. + * + * As the protocol version is a fixed value for a vsomeip implementation, + * it cannot be set. + */ + VSOMEIP_EXPORT virtual protocol_version_t get_protocol_version() const = 0; + + /** + * \brief Get the interface version from the message header. + */ + VSOMEIP_EXPORT virtual interface_version_t get_interface_version() const = 0; + + /** + * \brief Set the interface version in the message header. + */ + VSOMEIP_EXPORT virtual void set_interface_version(interface_version_t _version) = 0; + + /** + * \brief Get the message type from the message header. + */ + VSOMEIP_EXPORT virtual message_type_e get_message_type() const = 0; + + /** + * \brief Set the message type in the message header. + */ + VSOMEIP_EXPORT virtual void set_message_type(message_type_e _type) = 0; + + /** + * \brief Get the return code from the message header. + */ + VSOMEIP_EXPORT virtual return_code_e get_return_code() const = 0; + + /** + * \brief Set the return code in the message header. + */ + VSOMEIP_EXPORT virtual void set_return_code(return_code_e _code) = 0; + + /** + * \brief Return the transport mode that was/will be used to send the message. + */ + VSOMEIP_EXPORT virtual bool is_reliable() const = 0; + + /** + * \brief Set the transport mode that will be used to send the message. + */ + VSOMEIP_EXPORT virtual void set_reliable(bool _is_reliable) = 0; + + /** + * \brief Return whether or not the message is an initial event. + */ + VSOMEIP_EXPORT virtual bool is_initial() const = 0; + + /** + * \brief Set whether or not the message is an initial event. + */ + VSOMEIP_EXPORT virtual void set_initial(bool _is_initial) = 0; + +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_MESSAGE_BASE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/payload.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/payload.hpp new file mode 100644 index 00000000000..9b8ea95768e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/payload.hpp @@ -0,0 +1,106 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PAYLOAD_HPP_ +#define VSOMEIP_V3_PAYLOAD_HPP_ + +#include <vector> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +#include <vsomeip/internal/deserializable.hpp> +#include <vsomeip/internal/serializable.hpp> + +namespace vsomeip_v3 { + +/** + * + * \defgroup vsomeip + * + * @{ + * + */ + +/** + * + * \brief This class implements an array of bytes to be used as + * payload for SOME/IP messages. + * +*/ +class payload: public serializable, public deserializable { +public: + VSOMEIP_EXPORT virtual ~payload() {} + + /** + * \brief Returns true if the given payload is equal to this one. + * + * \param _other Payload that shall be compared to this payload. + */ + VSOMEIP_EXPORT virtual bool operator ==(const payload &_other) = 0; + + /** + * \brief Returns pointer to the payload content + */ + VSOMEIP_EXPORT virtual byte_t * get_data() = 0; + + /** + * \brief Returns constant pointer to the payload content + */ + VSOMEIP_EXPORT virtual const byte_t * get_data() const = 0; + + /** + * \brief Copies the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer remains untouched. + * + * \param _data Pointer to a data buffer. + * \param _length Length of the data buffer. + */ + VSOMEIP_EXPORT virtual void set_data(const byte_t *_data, + length_t _length) = 0; + + /** + * \brief Copies the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer remains untouched. + * + * \param _data Vector containing the data + */ + VSOMEIP_EXPORT virtual void set_data( + const std::vector<byte_t> &_data) = 0; + + /** + * \brief Returns the length of the payload content. + */ + VSOMEIP_EXPORT virtual length_t get_length() const = 0; + + /** + * \brief Set the maximum length of the payload content. + * + * This function must be called before directly copying data using the + * pointer to the internal buffer. + */ + VSOMEIP_EXPORT virtual void set_capacity(length_t _length) = 0; + + /** + * \brief Moves the given data array to the payload object. + * + * The current payload content is replaced by the data provided. + * The given buffer is owned by the payload object afterwards. + * + * \param _data Vector containing the data + */ + VSOMEIP_EXPORT virtual void set_data( + std::vector<byte_t> &&_data) = 0; +}; + +/** @} */ + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PAYLOAD_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugin.hpp new file mode 100644 index 00000000000..25ccbb2dc44 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugin.hpp @@ -0,0 +1,90 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PLUGIN_HPP_ +#define VSOMEIP_V3_PLUGIN_HPP_ + +#include <memory> +#include <string> + +#if _WIN32 + #if VSOMEIP_DLL_COMPILATION_PLUGIN + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllexport) + #else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN __declspec(dllimport) + #endif +#else + #define VSOMEIP_IMPORT_EXPORT_PLUGIN +#endif + +#define VSOMEIP_PLUGIN_INIT_SYMBOL "vsomeip_plugin_init" + +namespace vsomeip_v3 { + +enum class plugin_type_e : uint8_t { + APPLICATION_PLUGIN, + PRE_CONFIGURATION_PLUGIN, + CONFIGURATION_PLUGIN, + SD_RUNTIME_PLUGIN +}; + +class plugin; +typedef std::shared_ptr<plugin> (*create_plugin_func)(); +typedef create_plugin_func (*plugin_init_func)(); + +/** + * Base class for all plug-ins + */ +class VSOMEIP_IMPORT_EXPORT_PLUGIN plugin { +public: + virtual ~plugin() {} + + virtual uint32_t get_plugin_version() const = 0; + virtual const std::string &get_plugin_name() const = 0; + virtual plugin_type_e get_plugin_type() const = 0; +}; + +template<class Plugin_> +class plugin_impl : public plugin { +public: + static std::shared_ptr<plugin> get_plugin() { + return std::make_shared<Plugin_>(); + } + + plugin_impl(const std::string &_name, uint32_t _version, + plugin_type_e _type) { + name_ = _name; + version_ = _version; + type_ = _type; + } + + const std::string &get_plugin_name() const { + return name_; + } + + uint32_t get_plugin_version() const { + return version_; + } + + plugin_type_e get_plugin_type() const { + return type_; + } + +private: + uint32_t version_; + std::string name_; + plugin_type_e type_; +}; + +#define VSOMEIP_PLUGIN(class_name) \ + extern "C" { \ + VSOMEIP_EXPORT vsomeip_v3::create_plugin_func vsomeip_plugin_init() { \ + return class_name::get_plugin; \ + } \ + } + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PLUGIN_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/application_plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/application_plugin.hpp new file mode 100644 index 00000000000..a052aa2a3e8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/application_plugin.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_APPLICATION_PLUGIN_HPP_ +#define VSOMEIP_V3_APPLICATION_PLUGIN_HPP_ + +#include <string> +#include <memory> + +#include <vsomeip/export.hpp> + +// Version should be incremented on breaking API change +#define VSOMEIP_APPLICATION_PLUGIN_VERSION 1 + +namespace vsomeip_v3 { + +enum class application_plugin_state_e : uint8_t { + STATE_INITIALIZED, + STATE_STARTED, + STATE_STOPPED +}; + +/** + * The application plug-in can be used to extend application behavior + * via an module/plug-in. + */ +class application_plugin { +public: + virtual ~application_plugin() {} + + // Called by vSomeIP to inform an application plug-in about its actual state + // Call should not be blocked from plug-in as there is no threading. + // The caller thread of "application::init/::start/::stop" will inform the plug-in. + virtual void on_application_state_change(const std::string _application_name, + const application_plugin_state_e _app_state) = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_APPLICATION_PLUGIN_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/pre_configuration_plugin.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/pre_configuration_plugin.hpp new file mode 100644 index 00000000000..538599326bb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/plugins/pre_configuration_plugin.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PRE_CONFIGURATION_PLUGIN_HPP_ +#define VSOMEIP_V3_PRE_CONFIGURATION_PLUGIN_HPP_ + +#include <vsomeip/export.hpp> + +// Version should be incremented on breaking API change +#define VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION 1 + +namespace vsomeip_v3 { +/** + * The pre configuration plug-in can be used to extend configuration load behavior + * via an module/plug-in. + */ +class pre_configuration_plugin { +public: + virtual ~pre_configuration_plugin() {} + + // Plug-In should return a valid path to a vSomeIP configuration. + // vSomeIP will use this path for config loading if such a plug-in is availablel. + virtual std::string get_configuration_path() = 0; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PRE_CONFIGURATION_PLUGIN_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/primitive_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/primitive_types.hpp new file mode 100644 index 00000000000..a609f33ffd4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/primitive_types.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_PRIMITIVE_TYPES_HPP_ +#define VSOMEIP_V3_PRIMITIVE_TYPES_HPP_ + +#include <array> +#include <cstdint> +#include <string> + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <sys/types.h> +#endif + +namespace vsomeip_v3 { + +typedef uint32_t message_t; +typedef uint16_t service_t; +typedef uint16_t method_t; +typedef uint16_t event_t; + +typedef uint16_t instance_t; +typedef uint16_t eventgroup_t; + +typedef uint8_t major_version_t; +typedef uint32_t minor_version_t; + +typedef uint32_t ttl_t; + +typedef uint32_t request_t; +typedef uint16_t client_t; +typedef uint16_t session_t; + +typedef uint32_t length_t; + +typedef uint8_t protocol_version_t; +typedef uint8_t interface_version_t; + +typedef uint8_t byte_t; +typedef uint16_t diagnosis_t; + +typedef uint16_t port_t; + +// Addresses +typedef std::array<byte_t, 4> ipv4_address_t; +typedef std::array<byte_t, 16> ipv6_address_t; +typedef std::uint16_t port_t; + +typedef std::string trace_channel_t; + +typedef std::string trace_filter_type_t; + +typedef std::uint32_t pending_remote_offer_id_t; + +typedef std::uint32_t pending_security_update_id_t; + +#if defined(_WIN32) + typedef std::uint32_t uid_t; + typedef std::uint32_t gid_t; +#else + typedef ::uid_t uid_t; + typedef ::uid_t gid_t; +#endif + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_PRIMITIVE_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/runtime.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/runtime.hpp new file mode 100644 index 00000000000..e2d97c8ab6f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/runtime.hpp @@ -0,0 +1,236 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_RUNTIME_HPP +#define VSOMEIP_V3_RUNTIME_HPP + +#include <memory> +#include <string> +#include <vector> + +#include <vsomeip/export.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { + +class application; +class message; +class payload; + +/** + * + * \defgroup vsomeip + * + * The vsomeip module contains all elements a user applications needs to: + * + * - offer SOME/IP service instances + * - request SOME/IP service instances + * - offer SOME/IP eventgroups + * - subscribe to SOME/IP eventgroups + * - send and receive SOME/IP messages (request/response) + * - implement SOME/IP events and fields + * + * @{ + * + */ + +/** + * + * \brief Singleton class containing all public resource management + * facilities of vsomeip. + * + * The methods of this class shall be used to create instances of all the + * classes needed to facilitate SOME/IP communication. In particular, it is + * the entry point to create instances of the @ref application class that + * contains the main public API of vsomeip. + * + */ +class VSOMEIP_IMPORT_EXPORT runtime { +public: + + static std::string get_property(const std::string &_name); + static void set_property(const std::string &_name, const std::string &_value); + + static std::shared_ptr<runtime> get(); + + virtual ~runtime() { + } + + /** + * + * \brief Creates a vsomeip application object. + * + * An application object manages service offers and requests as well as + * event subscriptions. It allows to register user application functions + * as callbacks that are called on specific events during runtime, e.g + * to react on incoming SOME/IP messages. + * An application object is identified by a unique name that is also used + * in (and therefore has to match) the configuration files of vsomeip. If + * the name is left empty, the application name is taken from the + * environment variable "VSOMEIP_APPLICATION_NAME" + * + * \param _name Name of the application on the system. + * + */ + virtual std::shared_ptr<application> create_application( + const std::string &_name = "") = 0; + + /** + * + * \brief Constructs an empty message object. + * + * The message can then be used to call @application::send to send a + * SOME/IP message. The user application is responsible for setting + * the message type, the service instance and the message payload + * after this call and before calling @application::send. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + */ + virtual std::shared_ptr<message> create_message( + bool _reliable = false) const = 0; + /** + * + * \brief Constructs an empty request message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to REQUEST after the + * call and the request identifier is automatically set during the + * @ref application::send call. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + */ + virtual std::shared_ptr<message> create_request( + bool _reliable = false) const = 0; + + /* + * \brief Constructs an empty response message from a given request + * message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to RESPONSE after the + * call and the request identifier is automatically set from the + * request message. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _request The request message that shall be answered by + * the response message. + * + */ + virtual std::shared_ptr<message> create_response( + const std::shared_ptr<message> &_request) const = 0; + + /** + * + * \brief Creates an empty notification message. + * + * The message can then be used to call @ref application::send to send a + * SOME/IP message. The message type is set to NOTIFICATION after the + * call. + * + * The user application is responsible for setting the service instance + * and the payload. + * + * \param _reliable Determines whether this message shall be sent + * over a reliable connection (TCP) or not (UDP). + * + * Note: Creating notification messages and sending them using + * @ref application::send is possible but not the standard way of sending + * notification with vsomeip. The standard way is calling + * @ref application::offer_event and setting the value using the + * @ref application::notify / @ref application::notify_one methods. + * + */ + virtual std::shared_ptr<message> create_notification( + bool _reliable = false) const = 0; + + /** + * + * \brief Creates an empty payload object. + * + */ + virtual std::shared_ptr<payload> create_payload() const = 0; + + /** + * + * \brief Creates a payload object filled with the given data. + * + * \param _data Bytes to be copied into the payload object. + * \param _size Number of bytes to be copied into the payload object. + * + */ + virtual std::shared_ptr<payload> create_payload( + const byte_t *_data, uint32_t _size) const = 0; + + /** + * + * \brief Creates a payload object filled with the given data. + * + * \param _data Bytes to be copied into the payload object. + * + */ + virtual std::shared_ptr<payload> create_payload( + const std::vector<byte_t> &_data) const = 0; + + /** + * + * \brief Retrieves the application object for the application with the + * given name. + * + * If no such application is found, an empty shared_ptr is returned + * (nullptr). + * + * \param _name Name of the application to be found. + * + */ + virtual std::shared_ptr<application> get_application( + const std::string &_name) const = 0; + + /** + * + * \brief Removes the application object for the application with the + * given name. + * + * If no such application is found, this is a null operation. + * + * \param _name Name of the application to be removed. + * + */ + virtual void remove_application( const std::string &_name) = 0; + + /** + * + * \brief Creates a vsomeip application object. + * + * An application object manages service offers and requests as well as + * event subscriptions. It allows to register user application functions + * as callbacks that are called on specific events during runtime, e.g + * to react on incoming SOME/IP messages. + * An application object is identified by a unique name that is also used + * in (and therefore has to match) the configuration files of vsomeip. If + * the name is left empty, the application name is taken from the + * environment variable "VSOMEIP_APPLICATION_NAME" + * + * \param _name Name of the application on the system. + * \param _path Path to the configuration file or folder. + * + */ + virtual std::shared_ptr<application> create_application( + const std::string &_name, const std::string &_path) = 0; +}; + +/** @} */ + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_RUNTIME_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/structured_types.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/structured_types.hpp new file mode 100644 index 00000000000..565c20ca027 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/structured_types.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_STRUCTURED_TYPES_HPP_ +#define VSOMEIP_V3_STRUCTURED_TYPES_HPP_ + +#include <chrono> +#include <map> + +namespace vsomeip_v3 { + +// Messages are forwarded either because their value differs from the +// last received message (on_change) or because the specified time +// (interval) between two messages has elapsed. A message that is forwarded +// because of a changed value may reset the time until the next unchanged +// message is forwarded or not (on_change_resets_interval). By specifiying +// indexes and bit masks, the comparison that is carried out to decide whether +// or not two message values differ is configurable (ignore). +struct debounce_filter_t { + debounce_filter_t() + : on_change_(false), + on_change_resets_interval_(false), + interval_(-1), + send_current_value_after_(false) { + } + + debounce_filter_t(const debounce_filter_t &_source) + : on_change_(_source.on_change_), + on_change_resets_interval_(_source.on_change_resets_interval_), + interval_(_source.interval_), + ignore_(_source.ignore_), + send_current_value_after_(_source.send_current_value_after_) { + } + + inline void operator=(const debounce_filter_t &_other) { + on_change_ = _other.on_change_; + on_change_resets_interval_ = _other.on_change_resets_interval_; + interval_ = _other.interval_; + ignore_ = _other.ignore_; + send_current_value_after_ = _other.send_current_value_after_; + } + + inline bool operator==(const debounce_filter_t &_other) const { + + return (on_change_ == _other.on_change_ + && on_change_resets_interval_ == _other.on_change_resets_interval_ + && interval_ == _other.interval_ + && ignore_ == _other.ignore_ + && send_current_value_after_ == _other.send_current_value_after_); + } + + inline bool operator!=(const debounce_filter_t &_other) const { + + return (on_change_ != _other.on_change_ + || on_change_resets_interval_ != _other.on_change_resets_interval_ + || interval_ != _other.interval_ + || ignore_ != _other.ignore_ + || send_current_value_after_ != _other.send_current_value_after_); + } + + bool on_change_; + bool on_change_resets_interval_; + int64_t interval_; + std::map<std::size_t, byte_t> ignore_; + bool send_current_value_after_; +}; + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_STRUCTURED_TYPES_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/trace.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/trace.hpp new file mode 100644 index 00000000000..016dc5a7ece --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/trace.hpp @@ -0,0 +1,219 @@ +// Copyright (C) 2017-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_TRACE_HPP_ +#define VSOMEIP_V3_TRACE_HPP_ + +#include <memory> +#include <vector> + +#include <vsomeip/constants.hpp> +#include <vsomeip/primitive_types.hpp> + +namespace vsomeip_v3 { +/** + * \defgroup vsomeip + * + * @{ + */ +namespace trace { + +/** + * \brief Unique identifier for trace filters. + */ +typedef uint32_t filter_id_t; + +/** + * \brief Error value. + */ +extern const filter_id_t FILTER_ID_ERROR; + +/** + * \brief The default channel id "TC". + */ +extern const char *VSOMEIP_TC_DEFAULT_CHANNEL_ID; + +/** + * \brief Filters contain at least one match that specified + * which messages are filtered. + */ +typedef std::tuple<service_t, instance_t, method_t> match_t; + +/** + * \brief Representation of a DLT trace channel. + * + * A trace channel contains one or more filters that specify the + * messages that are forwarded to the trace. + */ +class channel { +public: + virtual ~channel() {}; + + /** + * \brief Get the identifier of the channel. + * + * \return Channel identifier. + */ + virtual std::string get_id() const = 0; + + /** + * \brief Get the name of the channel. + * + * \return Channel name. + */ + virtual std::string get_name() const = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a simple filter containing a single match. + * + * Note: The match is allowed to contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _match The tuple specifying the matching messages. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const match_t &_match, + bool _is_positive = true) = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a filter containing a list of matches to the + * channel. The filter matches if at least on of the + * matches corresponds to a message. + * + * Note: The matches are allowed to contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _matches List of tuples specifying the matching messages. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const std::vector<match_t> &_matches, + bool _is_positive = true) = 0; + + /** + * \brief Add a filter to the channel. + * + * Add a filter containing a matches range to the + * channel. The filter matches if the message identifiers + * lie within the range specified by from and to. Thus, + * the messages service identifier is greater equal than + * the service identifier specified in from and less equal + * than the service identifier specified in to. + * + * Note: from and to must not contain wildcards + * (ANY_INSTANCE, ANY_SERVICE, ANY_METHOD). + * + * \param _from Tuples specifying the matching message with + * the smallest identifiers. + * \param _from Tuples specifying the matching message with + * the greatest identifiers. + * \param _is_positive True for positive filters, + * false for negative filters. Default value is true. + * + * \return Filter identifier of the added filter or + * FILTER_ID_ERROR if adding failed. + */ + virtual filter_id_t add_filter( + const match_t &_from, const match_t &_to, + bool _is_positive = true) = 0; + + /** + * \brief Remove a filter from the channel. + * + * Remove the filter with the given filter identifier + * from the channel. + * + * \param _id Filter identifier of the filter that shall + * be removed. + */ + virtual void remove_filter( + filter_id_t _id) = 0; +}; + +/** + * \brief Singleton class to connect to the DLT tracing. + * + * The main configuration class of the DLT tracing. It holds + * the trace channels which determine the messages that are + * forwarded to the trace. + */ +class connector { +public: + /** + * \brief Get access to the connector. + * + * \return Shared pointer to the singleton object. + */ + static std::shared_ptr<connector> get(); + + virtual ~connector() {}; + + /** + * \brief Add a trace channel to the connector. + * + * Creates a trace channel with the given identifier and name + * and adds it to the connector. + * + * \param _id Id of the trace channel. + * \param _name Name of the trace channel + * + * \return Shared pointer to the created trace channel or + * nullptr if the trace channel could not be created because + * another trace channel with the given identifier does + * already exist. + */ + virtual std::shared_ptr<channel> add_channel( + const std::string &_id, + const std::string &_name) = 0; + + /** + * \brief Remove a trace channel from the connector. + * + * Removes the trace channel with the given identifier from + * the connector. + * + * \param _id Identifier of a trace channel. + * + * \return True of the trace channel was removed, False if + * it could not be removed, because it is the default trace + * channel. + */ + virtual bool remove_channel( + const std::string &_id) = 0; + + /** + * \brief Get a trace channel from the connector. + * + * \param _id Identifier of the trace channel to be returned. + * Optional argument that is predefined with the identifier + * of the default trace channel. + * + * \return Shared pointer to the created trace channel or + * nullptr if the trace channel does not exist. + */ + virtual std::shared_ptr<channel> get_channel( + const std::string &_id = VSOMEIP_TC_DEFAULT_CHANNEL_ID) const = 0; +}; + +} // namespace trace + +/** @} */ + +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_CONSTANTS_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip.hpp b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip.hpp new file mode 100644 index 00000000000..f0a66c5e564 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_VSOMEIP_HPP +#define VSOMEIP_VSOMEIP_HPP + +/** + * \brief The central vsomeip header. Include this to use vsomeip. + */ + +#include <vsomeip/constants.hpp> +#include <vsomeip/defines.hpp> +#include <vsomeip/application.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/trace.hpp> + +namespace vsomeip = vsomeip_v3; + +#endif // VSOMEIP_VSOMEIP_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip_sec.h b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip_sec.h new file mode 100644 index 00000000000..aadcf374d47 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/interface/vsomeip/vsomeip_sec.h @@ -0,0 +1,153 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_SECURITY_VSOMEIP_SEC_H_ +#define VSOMEIP_V3_SECURITY_VSOMEIP_SEC_H_ + +#define VSOMEIP_SEC_PORT_UNUSED 0 +#define VSOMEIP_SEC_PORT_UNSET 0xFFFF + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <sys/types.h> + +typedef uint16_t vsomeip_sec_service_id_t; +typedef uint16_t vsomeip_sec_instance_id_t; +typedef uint16_t vsomeip_sec_member_id_t; // SOME/IP method or event + +typedef uint32_t vsomeip_sec_ip_addr_t; // ip address in network byte order +typedef uint16_t vsomeip_sec_network_port_t; // network port in network byte order + +#ifndef __unix__ +typedef uint32_t uid_t; +typedef uint32_t gid_t; +#endif + +typedef struct { + uid_t user; + gid_t group; + + vsomeip_sec_ip_addr_t host; + vsomeip_sec_network_port_t port; // VSOMEIP_SEC_PORT_UNUSED --> UDS; ]0, VSOMEIP_SEC_PORT_UNSET] --> TCP +} vsomeip_sec_client_t; + +typedef enum { + VSOMEIP_SEC_OK, + VSOMEIP_SEC_PERM_DENIED +} vsomeip_sec_acl_result_t; + +typedef enum { + VSOMEIP_SEC_POLICY_OK, + VSOMEIP_SEC_POLICY_NOT_FOUND, + VSOMEIP_SEC_POLICY_INVALID +} vsomeip_sec_policy_result_t; + +/** + * Load the policy and initialize policy plugin functionality. + * This function MUST be called before any other function in this library can be called. + * It will return whether loading the policy was successful or if there was some problem + * during initialization. + * + * Please note that the policy initializer does not take any additional arguments. It is assumed + * here tha the policy plugin libraries have some out-of-bounds methods to, e.g., find the policy + * file. + * + * The function may be called multiple times (even from multiple threads) without problems. + */ + vsomeip_sec_policy_result_t vsomeip_sec_policy_initialize(); + +/** + * Authenticate connection with vSomeIP router. + * + * vSomeIP router (vsomeipd) has by definition unlimited access to other vSomeIP applications. + * Therefore, EVERY connection with the router must be authenticated and then any command from/to + * vsomeipd is implicitly allowed. + * + * This method MUST be called to ensure that the remote end is supposed to act as + * vSomeIP routing manager. + * + */ +vsomeip_sec_acl_result_t vsomeip_sec_policy_authenticate_router(const vsomeip_sec_client_t *router); + + +/* + * ### RPC + */ + +/** + * Check if a server is authorised to offer a specific service / instance + * + * vsomeip_sec_policy_is_client_allowed_to_offer checks if \p server is allowed to offer a \p + * service by the security policy. + * + * This API MUST be called by vSomeIP clients before sending requests and before + * processing responses. It and SHOULD be called at the router for every service offer before + * distributing it among the clients. + * + * @note + * Both, method calls and subscribe-notify communications are end-to-end + * authenticated. Therefore, authentication of the server at the router side is optional but + * recommended. Doing so would help to detect system missconfiguration and simplify + * application debugging. + * + * @note + * Due to asynchronous nature of SOME/IP method calls, to deliver a method response, server + * establishes a separate socket which destination client must be authenticated. This method + * does exactly that. + * + * @note + * While client access may be restricted to certain methods or events, servers are always + * allowed to offer. + */ +vsomeip_sec_acl_result_t vsomeip_sec_policy_is_client_allowed_to_offer( + const vsomeip_sec_client_t *server, + vsomeip_sec_service_id_t service, vsomeip_sec_instance_id_t instance); + + + +/** + * Check if client is allowed to request a service. + * + * This method MUST be called at the server/stub side before serving a client request. It may + * additionally be used by vsomeipd when servicing service discovery so that clients that do not + * have the permission to request a certain service cannot (even) successfully discover it. + * + */ +vsomeip_sec_acl_result_t vsomeip_sec_policy_is_client_allowed_to_request( + const vsomeip_sec_client_t *client, + vsomeip_sec_service_id_t service, vsomeip_sec_instance_id_t instance); + + +/** + * Check if client is allowed to access a specific SOME/IP method. + * + * SOME/IP does not really distinguish between methods and events. It just handles everything + * via a uint16 member identifier. The identifiers below 0x7FFF are used for methods, identifier + * starting at 0x8000 are used for events. So we just have one method to check if the client is + * allowed to interact with a specific member. + * + * This method MUST be called at the server/stub side before processing a request that triggers + * a specific method or completes event registration. + */ +vsomeip_sec_acl_result_t vsomeip_sec_policy_is_client_allowed_to_access_member( + const vsomeip_sec_client_t *client, + vsomeip_sec_service_id_t service, vsomeip_sec_instance_id_t instance, vsomeip_sec_member_id_t member); + + +/** + * Provides user and group identifiers for a given host address / port combination. + * + * Note: For UDS (aka port=0), calling this function is a no-op. + */ +void vsomeip_sec_sync_client(vsomeip_sec_client_t *client); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VSOMEIP_V3_SECURITY_VSOMEIP_SEC_H_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/libvsomeip.yaml b/lib/libsomeip-c/vsomeip-3.5.1/libvsomeip.yaml new file mode 100644 index 00000000000..eccc62c2af1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/libvsomeip.yaml @@ -0,0 +1,6 @@ +- name: libvsomeip + version: 3.5.1 + vendor: Lynx Team + license: + concluded: CLOSED and MPLv2 + declared: MPLv2 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/CMakeLists.txt new file mode 100644 index 00000000000..87a099fd00c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/CMakeLists.txt @@ -0,0 +1,148 @@ +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +############################################################################## +# Test section +############################################################################## + +############################################################################## +# google benchmark +find_package(benchmark) + +############################################################################## +# google test + +# remove export symbols from the cxx flags +string(REPLACE "${EXPORTSYMBOLS}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +# check for set environment variable +if(${GTEST_ROOT} STREQUAL "n/a") + message(STATUS "GTEST_ROOT is not defined. For building the tests the variable + GTEST_ROOT has to be defined. Tests can not be built.") + # early exit + return() # test can not be build -> make commands build_tests and check are not available +else() + message(STATUS "GTEST_ROOT is set. gtest root path set to ${GTEST_ROOT}") +endif() + +# build google test as static library (always) -> therefore deactivate BUILD_SHARED_LIBS in case it is active +set(BUILD_SHARED_LIBS_AUTOMATIC_OFF 0) +if ("${BUILD_SHARED_LIBS}" STREQUAL "ON") + set(BUILD_SHARED_LIBS OFF) + set(BUILD_SHARED_LIBS_AUTOMATIC_OFF 1) +endif() +add_subdirectory(${GTEST_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/gtest EXCLUDE_FROM_ALL) +if ("${BUILD_SHARED_LIBS_AUTOMATIC_OFF}" STREQUAL "1") + set(BUILD_SHARED_LIBS ON) + set(BUILD_SHARED_LIBS_AUTOMATIC_OFF 0) +endif() + +############################################################################## +# build tests + +SET(TESTS_BAT "OFF" CACHE BOOL +"Controls whether only BAT tests should be build or not") +SET(TEST_SYMLINK_CONFIG_FILES "OFF" CACHE BOOL +"Controls if the json and scripts needed needed to run the tests are copied or symlinked into the build directroy (ignored on Windows)") +SET(TEST_SYMLINK_CONFIG_FILES_RELATIVE "OFF" CACHE BOOL + "Controls if the json and scripts needed needed to run the tests are symlinked relatively into the build directroy (ignored on Windows)") + +SET(TEST_IP_DEFAULT_VALUE "XXX.XXX.XXX.XXX") +SET(TEST_IP_MASTER "${TEST_IP_DEFAULT_VALUE}" CACHE STRING + "The IP address of the interface which will act as test master") + SET(TEST_IP_SLAVE "${TEST_IP_DEFAULT_VALUE}" CACHE STRING + "The IP address of the interface which will act as test slave") + +if((${TEST_IP_MASTER} STREQUAL ${TEST_IP_DEFAULT_VALUE}) OR + (${TEST_IP_SLAVE} STREQUAL ${TEST_IP_DEFAULT_VALUE})) + message(WARNING "TEST_IP_MASTER and/or TEST_IP_SLAVE isn't set. " + "Remote tests cannot be run. " + "To enable, please specify for example " + "-DTEST_IP_MASTER=10.0.3.1 -DTEST_IP_SLAVE=10.0.3.2") +endif() + +SET(TEST_IP_SLAVE_SECOND "${TEST_IP_DEFAULT_VALUE}" CACHE STRING +"The second IP address of the interface which will act as test slave") +set(TEST_SECOND_ADDRESS "OFF" CACHE BOOL + "Controls whether second address tests should run or not") + +if(${TEST_IP_SLAVE_SECOND} STREQUAL ${TEST_IP_DEFAULT_VALUE}) + message(WARNING "TEST_IP_SLAVE_SECOND isn't set. " + "Test with more than one IP address on same interface is not enabled." + "Please specify them via for example " + "-TEST_IP_SLAVE_SECOND=10.0.3.126") +else() + set(TEST_SECOND_ADDRESS "ON") +endif() + +set(TEST_E2E_PROFILE_04 "ON") +set(TEST_E2E_PROFILE_07 "ON") + +SET(TEST_UID_DEFAULT_VALUE "123456789") +SET(TEST_UID "${TEST_UID_DEFAULT_VALUE}" CACHE STRING + "The User ID of the user running the test: Needed for security") +SET(TEST_GID_DEFAULT_VALUE "123456789") +SET(TEST_GID "${TEST_GID_DEFAULT_VALUE}" CACHE STRING +"The Group ID of the user running the test: Needed for security") + +SET(TEST_SECURITY "ON" CACHE BOOL +"Controls whether security tests should run or not") + +if((${TEST_UID} STREQUAL ${TEST_UID_DEFAULT_VALUE}) OR + (${TEST_GID} STREQUAL ${TEST_GID_DEFAULT_VALUE}) OR + DISABLE_SECURITY) + message(WARNING "TEST_UID and/or TEST_GID isn't set. " + "Security Tests are not runnable " + "Please specify them for example " + "-DTEST_UID=1000 -DTEST_GID=1000") + SET(TEST_SECURITY "OFF") +endif() + +add_custom_target(build_tests) + +set(CMAKE_CTEST_COMMAND ctest -V) +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) +add_dependencies(check build_tests) + +add_custom_target(build_network_tests) +add_dependencies(build_network_tests ${VSOMEIP_NAME}) +add_dependencies(build_network_tests ${VSOMEIP_NAME}-e2e) +add_dependencies(build_network_tests ${VSOMEIP_NAME}-sd) +add_dependencies(build_tests build_network_tests) + +add_custom_target(build_unit_tests) +add_dependencies(build_unit_tests ${VSOMEIP_NAME}) +add_dependencies(build_unit_tests ${VSOMEIP_NAME}-sd) +add_dependencies(build_tests build_unit_tests) + +add_custom_target(build_benchmark_tests) +add_dependencies(build_benchmark_tests ${VSOMEIP_NAME}) +add_dependencies(build_benchmark_tests ${VSOMEIP_NAME}-sd) +add_dependencies(build_tests build_benchmark_tests) + +############################################################################## +# add network, unit and benchmark tests directories +############################################################################## + +add_subdirectory(common EXCLUDE_FROM_ALL) +add_subdirectory(network_tests EXCLUDE_FROM_ALL) + +if (NOT DISABLE_SECURITY) + add_subdirectory(unit_tests EXCLUDE_FROM_ALL) + + if(benchmark_FOUND) + add_subdirectory(benchmark_tests EXCLUDE_FROM_ALL) + endif() +endif() + +############################################################################## +# Add internal_routing_disabled_acceptance_test +############################################################################## + +if(NOT ${TESTS_BAT}) + add_subdirectory(internal_routing_disabled_acceptance_test) +endif() + +configure_file(tsan-suppressions.txt tsan-suppressions.txt COPYONLY) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/excluded_tests.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/excluded_tests.txt new file mode 100644 index 00000000000..d90fe5681b4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/excluded_tests.txt @@ -0,0 +1,120 @@ +application_test_single_process +application_test_availability +big_payload_test_external +big_payload_test_external_random +big_payload_test_external_limited +big_payload_test_external_limited_general +big_payload_test_external_queue_limited_general +big_payload_test_external_queue_limited_specific +big_payload_test_external_udp +big_payload_test_local_limited +big_payload_test_local_queue_limited +big_payload_test_local_random +big_payload_test_local_tcp_queue_limited +big_payload_test_local_tcp_limited +big_payload_test_local_tcp_random +big_payload_test_local_tcp +configuration_test +client_id_test_diff_client_ids_diff_ports +client_id_test_diff_client_ids_same_ports +client_id_test_diff_client_ids_partial_same_ports +client_id_test_utility_discontinuous_masked_511 +client_id_test_utility_masked_127 +client_id_test_utility_masked_4095 +client_id_test_utility_masked_511 +client_id_test_utility +cpu_load_test +debounce_test +e2e_profile_04_test_external +e2e_test_external +event_test_payload_fixed_udp +event_test_payload_fixed_tcp +event_test_payload_dynamic_udp +event_test_payload_dynamic_tcp +initial_event_test_diff_client_ids_diff_ports_udp +initial_event_test_diff_client_ids_diff_ports_tcp +initial_event_test_diff_client_ids_diff_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_same_ports_udp +initial_event_test_diff_client_ids_same_ports_tcp +initial_event_test_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_tcp +initial_event_test_multiple_events_diff_client_ids_diff_ports_both_tcp_and_udp +initial_event_test_multiple_events_diff_client_ids_same_ports_udp +initial_event_test_multiple_events_diff_client_ids_same_ports_tcp +initial_event_test_multiple_events_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_tcp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_both_tcp_and_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_tcp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_partial_same_ports_both_tcp_and_udp +initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_same_service_id_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_tcp +initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_both_tcp_and_udp +initial_event_test_diff_client_ids_same_ports_udp_client_subscribes_twice +magic_cookies_test +external_local_routing_test +malicious_data_test_events +malicious_data_test_protocol_version +malicious_data_test_message_type +malicious_data_test_return_code +malicious_data_test_wrong_header_fields_udp +npdu_test_udp +npdu_test_tcp +offer_test_local +offer_test_big_sd_msg +offer_test_external +offered_services_info_test_local +local_payload_test_huge_payload +external_local_payload_test_client_external +external_local_payload_test_client_local_and_external +external_local_routing_test_starter +pending_subscription_test_subscribe +pending_subscription_test_alternating_subscribe_unsubscribe +pending_subscription_test_unsubscribe +pending_subscription_test_alternating_subscribe_unsubscribe_nack +pending_subscription_test_alternating_subscribe_unsubscribe_same_port +pending_subscription_test_subscribe_resubscribe_mixed +pending_subscription_test_subscribe_stopsubscribe_subscribe +pending_subscription_test_send_request_to_sd_port +restart_routing_test +someip_tp_test_in_sequence +someip_tp_test_mixed +someip_tp_test_incomplete +someip_tp_test_duplicate +someip_tp_test_overlap +someip_tp_test_overlap_front_back +subscribe_notify_one_test_diff_client_ids_diff_ports_udp +subscribe_notify_one_test_diff_client_ids_diff_ports_tcp +subscribe_notify_one_test_diff_client_ids_diff_ports_both_tcp_and_udp +subscribe_notify_test_diff_client_ids_diff_ports_udp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_udp +subscribe_notify_test_diff_client_ids_diff_ports_tcp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_tcp +subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp +subscribe_notify_test_diff_client_ids_same_ports_udp_local_tcp +subscribe_notify_test_diff_client_ids_same_ports_tcp_local_tcp +subscribe_notify_test_diff_client_ids_same_ports_tcp +subscribe_notify_test_diff_client_ids_same_ports_udp +subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp_local_tcp +subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp +subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp_local_tcp +subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp +subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp +subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp +subscribe_notify_test_one_event_two_eventgroups_udp_local_tcp +subscribe_notify_test_one_event_two_eventgroups_tcp_local_tcp +subscribe_notify_test_one_event_two_eventgroups_udp +subscribe_notify_test_one_event_two_eventgroups_tcp +suspend_resume_test_initial +internal_routing_disabled_acceptance_test diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/sdk_vsomeip_tests.py b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/sdk_vsomeip_tests.py new file mode 100644 index 00000000000..3ea5e8dbcb8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/sdk_vsomeip_tests.py @@ -0,0 +1,42 @@ +# Copyright (C) 2023. BMW Car IT GmbH. All rights reserved. + +# Test it with: +# run-mgu-tests -v --sdktarget xs-baytrail-hmgua1 --sysroot / /usr/share/vsomeip-sdktests/sdktests/sdk_vsomeip_tests.py + +import os +import shutil +import tempfile + +import subprocess +if not hasattr(subprocess, "TimeoutExpired"): + import subprocess32 as subprocess + +from mtee.testing.tools import assert_true, assert_equal, metadata + +@metadata(testsuite="BAT", component="vsomeip", teststage="regression") +class TestsSdkVSomeIP(object): + + def setup(self): + TestsSdkVSomeIP._srcdir = os.path.dirname(os.path.realpath(__file__)); + TestsSdkVSomeIP._tempdir = tempfile.mkdtemp() + + def teardown(self): + if os.path.isdir(TestsSdkVSomeIP._tempdir): + shutil.rmtree(TestsSdkVSomeIP._tempdir) + + @staticmethod + def run_command(cmd, cwd=None, input=None): + if cwd==None: cwd=os.getcwd() + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False,cwd=cwd) + if input: proc.stdin.write(input.encode('utf-8')) + (stdo,stde)=proc.communicate() + stdo = stdo.decode('utf-8') if stdo else None + stde = stde.decode('utf-8') if stde else None + assert_equal(0, proc.returncode, "Running command failed") + + def test_001_hello_world(self): + TestsSdkVSomeIP.run_command(["cmake", os.path.join(TestsSdkVSomeIP._srcdir, "hello_world")], cwd=TestsSdkVSomeIP._tempdir) + TestsSdkVSomeIP.run_command(["make"], cwd=TestsSdkVSomeIP._tempdir) + + assert_true(os.path.isfile(os.path.join(TestsSdkVSomeIP._tempdir, "hello_world_service")), "hello_world_service not created") + assert_true(os.path.isfile(os.path.join(TestsSdkVSomeIP._tempdir, "hello_world_client")), "hello_world_client not created") diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/test-metadata.json b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/test-metadata.json new file mode 100644 index 00000000000..74b9834e2c0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/test-metadata.json @@ -0,0 +1,1088 @@ +[ + { + "name": "configuration-test", + "command": [ + "configuration-test" + ], + "environment": {} + }, + { + "name": "application_test", + "command": [ + "application_test_starter.sh" + ], + "environment": {} + }, + { + "name": "application_test_single_process", + "command": [ + "application_test_single_process_starter.sh" + ], + "environment": {} + }, + { + "name": "application_test_availability", + "command": [ + "application_test_availability_starter.sh" + ], + "environment": {} + }, + { + "name": "magic_cookies_test", + "command": [ + "magic_cookies_test_starter.sh" + ], + "environment": {} + }, + { + "name": "header_factory_test", + "command": [ + "header_factory_test" + ], + "environment": {} + }, + { + "name": "header_factory_test_send_receive", + "command": [ + "header_factory_test_send_receive_starter.sh" + ], + "environment": {} + }, + { + "name": "local_routing_test", + "command": [ + "local_routing_test_starter.sh" + ], + "environment": {} + }, + { + "name": "external_local_routing_test", + "command": [ + "external_local_routing_test_starter.sh" + ], + "environment": {} + }, + { + "name": "local_payload_test", + "command": [ + "local_payload_test_starter.sh" + ], + "environment": {} + }, + { + "name": "local_payload_test_huge_payload", + "command": [ + "local_payload_test_huge_payload_starter.sh" + ], + "environment": {} + }, + { + "name": "external_local_payload_test_client_local", + "command": [ + "external_local_payload_test_client_local_starter.sh" + ], + "environment": {} + }, + { + "name": "external_local_payload_test_client_external", + "command": [ + "external_local_payload_test_client_external_starter.sh" + ], + "environment": {} + }, + { + "name": "external_local_payload_test_client_local_and_external", + "command": [ + "external_local_payload_test_client_local_and_external_starter.sh" + ], + "environment": {} + }, + { + "name": "big_payload_test_local", + "command": [ + "big_payload_test_local_starter.sh" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_random", + "command": [ + "big_payload_test_local_starter.sh", + "RANDOM" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_limited", + "command": [ + "big_payload_test_local_starter.sh", + "LIMITED" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_queue_limited", + "command": [ + "big_payload_test_local_starter.sh", + "QUEUELIMITEDGENERAL" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_tcp", + "command": [ + "big_payload_test_local_tcp_starter.sh" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_tcp_random", + "command": [ + "big_payload_test_local_tcp_starter.sh", + "RANDOM" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_tcp_limited", + "command": [ + "big_payload_test_local_tcp_starter.sh", + "LIMITED" + ], + "environment": {} + }, + { + "name": "big_payload_test_local_tcp_queue_limited", + "command": [ + "big_payload_test_local_tcp_starter.sh", + "QUEUELIMITEDGENERAL" + ], + "environment": {} + }, + { + "name": "big_payload_test_external", + "command": [ + "big_payload_test_external_starter.sh" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_random", + "command": [ + "big_payload_test_external_starter.sh", + "RANDOM" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_limited", + "command": [ + "big_payload_test_external_starter.sh", + "LIMITED" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_limited_general", + "command": [ + "big_payload_test_external_starter.sh", + "LIMITEDGENERAL" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_queue_limited_general", + "command": [ + "big_payload_test_external_starter.sh", + "QUEUELIMITEDGENERAL" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_queue_limited_specific", + "command": [ + "big_payload_test_external_starter.sh", + "QUEUELIMITEDSPECIFIC" + ], + "environment": {} + }, + { + "name": "big_payload_test_external_udp", + "command": [ + "big_payload_test_external_starter.sh", + "UDP" + ], + "environment": {} + }, + { + "name": "client_id_test_diff_client_ids_diff_ports", + "command": [ + "client_id_test_master_starter.sh", + "client_id_test_diff_client_ids_diff_ports_master.json" + ], + "environment": {} + }, + { + "name": "client_id_test_diff_client_ids_same_ports", + "command": [ + "client_id_test_master_starter.sh", + "client_id_test_diff_client_ids_same_ports_master.json" + ], + "environment": {} + }, + { + "name": "client_id_test_diff_client_ids_partial_same_ports", + "command": [ + "client_id_test_master_starter.sh", + "client_id_test_diff_client_ids_partial_same_ports_master.json" + ], + "environment": {} + }, + { + "name": "client_id_test_utility", + "command": [ + "client_id_test_utility" + ], + "environment": { + "VSOMEIP_CONFIGURATION": "client_id_test_utility.json" + } + }, + { + "name": "client_id_test_utility_masked_511", + "command": [ + "client_id_test_utility" + ], + "environment": { + "VSOMEIP_CONFIGURATION": "client_id_test_utility_masked_511.json" + } + }, + { + "name": "client_id_test_utility_masked_4095", + "command": [ + "client_id_test_utility" + ], + "environment": { + "VSOMEIP_CONFIGURATION": "client_id_test_utility_masked_4095.json" + } + }, + { + "name": "client_id_test_utility_masked_127", + "command": [ + "client_id_test_utility" + ], + "environment": { + "VSOMEIP_CONFIGURATION": "client_id_test_utility_masked_127.json" + } + }, + { + "name": "client_id_test_utility_discontinuous_masked_511", + "command": [ + "client_id_test_utility" + ], + "environment": { + "VSOMEIP_CONFIGURATION": "client_id_test_utility_discontinuous_masked_511.json" + } + }, + { + "name": "debounce_test", + "command": [ + "debounce_test_master_starter.sh" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_tcp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP", + "subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_tcp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP", + "subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json", + "SAME_SERVICE_ID" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp_local_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_one_event_two_eventgroups_udp_local_tcp", + "command": [ + "subscribe_notify_test_one_event_two_eventgroups_master_starter.sh", + "UDP", + "subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_one_event_two_eventgroups_tcp_local_tcp", + "command": [ + "subscribe_notify_test_one_event_two_eventgroups_master_starter.sh", + "TCP", + "subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP", + "subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_same_ports_master_udp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_tcp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP", + "subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_same_ports_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_test_diff_client_ids_partial_same_ports_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json", + "SAME_SERVICE_ID" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp", + "command": [ + "subscribe_notify_test_master_starter.sh", + "UDP", + "subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_one_event_two_eventgroups_udp", + "command": [ + "subscribe_notify_test_one_event_two_eventgroups_master_starter.sh", + "UDP", + "subscribe_notify_test_one_event_two_eventgroups_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_test_one_event_two_eventgroups_tcp", + "command": [ + "subscribe_notify_test_one_event_two_eventgroups_master_starter.sh", + "TCP", + "subscribe_notify_test_one_event_two_eventgroups_master.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_one_test_diff_client_ids_diff_ports_udp", + "command": [ + "subscribe_notify_one_test_master_starter.sh", + "UDP", + "subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_one_test_diff_client_ids_diff_ports_tcp", + "command": [ + "subscribe_notify_one_test_master_starter.sh", + "TCP", + "subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json" + ], + "environment": {} + }, + { + "name": "subscribe_notify_one_test_diff_client_ids_diff_ports_both_tcp_and_udp", + "command": [ + "subscribe_notify_one_test_master_starter.sh", + "TCP_AND_UDP", + "subscribe_notify_one_test_diff_client_ids_diff_ports_master.json" + ], + "environment": {} + }, + { + "name": "cpu_load_test", + "command": [ + "cpu_load_test_master_starter.sh" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_diff_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_udp.json", + "UDP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_diff_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_tcp.json", + "TCP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_diff_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master.json", + "TCP_AND_UDP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_same_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_udp.json", + "UDP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_same_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_tcp.json", + "TCP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master.json", + "TCP_AND_UDP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_partial_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_partial_same_ports_master.json", + "TCP_AND_UDP" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_diff_ports_same_service_id_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json", + "TCP_AND_UDP", + "SAME_SERVICE_ID" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_udp.json", + "UDP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_tcp.json", + "TCP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_same_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_udp.json", + "UDP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_same_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_tcp.json", + "TCP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_partial_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_partial_same_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_same_service_id_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json", + "TCP_AND_UDP", + "SAME_SERVICE_ID", + "MULTIPLE_EVENTS" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_udp.json", + "UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_tcp.json", + "TCP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_udp.json", + "UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_tcp.json", + "TCP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_partial_same_ports_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_partial_same_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_same_service_id_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json", + "TCP_AND_UDP", + "SAME_SERVICE_ID", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ON_AVAILABILITY" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_udp.json", + "UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ONLY_ONE" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_tcp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master_tcp.json", + "TCP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ONLY_ONE" + ], + "environment": {} + }, + { + "name": "initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_both_tcp_and_udp", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_diff_ports_master.json", + "TCP_AND_UDP", + "MULTIPLE_EVENTS", + "SUBSCRIBE_ONLY_ONE" + ], + "environment": {} + }, + { + "name": "initial_event_test_diff_client_ids_same_ports_udp_client_subscribes_twice", + "command": [ + "initial_event_test_master_starter.sh", + "initial_event_test_diff_client_ids_same_ports_master_udp.json", + "UDP", + "CLIENT_SUBSCRIBES_TWICE" + ], + "environment": {} + }, + { + "name": "offer_test_local", + "command": [ + "offer_test_local_starter.sh" + ], + "environment": {} + }, + { + "name": "offer_test_external", + "command": [ + "offer_test_external_master_starter.sh" + ], + "environment": {} + }, + { + "name": "offer_test_big_sd_msg", + "command": [ + "offer_test_big_sd_msg_master_starter.sh" + ], + "environment": {} + }, + { + "name": "offered_services_info_test_local", + "command": [ + "offered_services_info_test_local_starter.sh" + ], + "environment": {} + }, + { + "name": "restart_routing_test", + "command": [ + "restart_routing_test_starter.sh" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_subscribe", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_alternating_subscribe_unsubscribe", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE_UNSUBSCRIBE" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_unsubscribe", + "command": [ + "pending_subscription_test_master_starter.sh", + "UNSUBSCRIBE" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_alternating_subscribe_unsubscribe_nack", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE_UNSUBSCRIBE_NACK" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_alternating_subscribe_unsubscribe_same_port", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE_UNSUBSCRIBE_SAME_PORT" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_subscribe_resubscribe_mixed", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE_RESUBSCRIBE_MIXED" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_subscribe_stopsubscribe_subscribe", + "command": [ + "pending_subscription_test_master_starter.sh", + "SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE" + ], + "environment": {} + }, + { + "name": "pending_subscription_test_send_request_to_sd_port", + "command": [ + "pending_subscription_test_master_starter.sh", + "REQUEST_TO_SD" + ], + "environment": {} + }, + { + "name": "malicious_data_test_events", + "command": [ + "malicious_data_test_master_starter.sh", + "MALICIOUS_EVENTS" + ], + "environment": {} + }, + { + "name": "malicious_data_test_protocol_version", + "command": [ + "malicious_data_test_master_starter.sh", + "PROTOCOL_VERSION" + ], + "environment": {} + }, + { + "name": "malicious_data_test_message_type", + "command": [ + "malicious_data_test_master_starter.sh", + "MESSAGE_TYPE" + ], + "environment": {} + }, + { + "name": "malicious_data_test_return_code", + "command": [ + "malicious_data_test_master_starter.sh", + "RETURN_CODE" + ], + "environment": {} + }, + { + "name": "malicious_data_test_wrong_header_fields_udp", + "command": [ + "malicious_data_test_master_starter.sh", + "WRONG_HEADER_FIELDS_UDP" + ], + "environment": {} + }, + { + "name": "npdu_test_udp", + "command": [ + "npdu_test_starter.sh", + "UDP", + "sync" + ], + "environment": {} + }, + { + "name": "npdu_test_tcp", + "command": [ + "npdu_test_starter.sh", + "TCP", + "sync" + ], + "environment": {} + }, + { + "name": "e2e_test_external", + "command": [ + "e2e_test_external_master_start.sh", + "e2e_test_client_external.json" + ], + "environment": {} + }, + { + "name": "e2e_profile_04_test_external", + "command": [ + "e2e_profile_04_test_external_master_start.sh", + "e2e_profile_04_test_client_external.json" + ], + "environment": {} + }, + { + "name": "event_test_payload_fixed_udp", + "command": [ + "event_test_master_starter.sh", + "PAYLOAD_FIXED", + "UDP" + ], + "environment": {} + }, + { + "name": "event_test_payload_fixed_tcp", + "command": [ + "event_test_master_starter.sh", + "PAYLOAD_FIXED", + "TCP" + ], + "environment": {} + }, + { + "name": "event_test_payload_dynamic_udp", + "command": [ + "event_test_master_starter.sh", + "PAYLOAD_DYNAMIC", + "UDP" + ], + "environment": {} + }, + { + "name": "event_test_payload_dynamic_tcp", + "command": [ + "event_test_master_starter.sh", + "PAYLOAD_DYNAMIC", + "TCP" + ], + "environment": {} + }, + { + "name": "someip_tp_test_in_sequence", + "command": [ + "someip_tp_test_master_starter.sh", + "IN_SEQUENCE" + ], + "environment": {} + }, + { + "name": "someip_tp_test_mixed", + "command": [ + "someip_tp_test_master_starter.sh", + "MIXED" + ], + "environment": {} + }, + { + "name": "someip_tp_test_incomplete", + "command": [ + "someip_tp_test_master_starter.sh", + "INCOMPLETE" + ], + "environment": {} + }, + { + "name": "someip_tp_test_duplicate", + "command": [ + "someip_tp_test_master_starter.sh", + "DUPLICATE" + ], + "environment": {} + }, + { + "name": "someip_tp_test_overlap", + "command": [ + "someip_tp_test_master_starter.sh", + "OVERLAP" + ], + "environment": {} + }, + { + "name": "someip_tp_test_overlap_front_back", + "command": [ + "someip_tp_test_master_starter.sh", + "OVERLAP_FRONT_BACK" + ], + "environment": {} + }, + { + "name": "suspend_resume_test_initial", + "command": [ + "suspend_resume_test_master_starter.sh", + "SERVICE" + ], + "environment": {} + }, + { + "name": "internal_routing_disabled_acceptance_test", + "command": [ + "internal_routing_disabled_acceptance_test/internal_routing_disabled_acceptance_test" + ], + "environment": { + "LD_LIBRARY_PATH": "build", + "VSOMEIP_CONFIGURATION": "internal_routing_disabled_acceptance_test/vsomeip.json" + } + } +] diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_socket_path_tests.py b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_socket_path_tests.py new file mode 100644 index 00000000000..4228840adf5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_socket_path_tests.py @@ -0,0 +1,29 @@ +# Copyright (C) 2023. BMW Car IT GmbH. All rights reserved. +import os +import nose + +from mtee.testing.support.target_share import TargetShare +from mtee.testing.tools import metadata, assert_process_returncode +from mtee.testing.test_environment import require_environment, TEST_ENVIRONMENT as te + +from nose.tools import assert_regexp_matches, assert_true, assert_equal, assert_not_equal + +# test needs a target for execution +target = TargetShare().target + +TEST_ENVIRONMENT = (te.target.hardware.mgu22, ) + +@require_environment(*TEST_ENVIRONMENT) +@metadata(testsuite=["BAT", "domain"], + component="vsomeip", + domain="SYSMAN", + duration="short", + priority=1, + testlevel="ENG_07", + teststage="regression") +class TestTargetVSomeIP(object): + + @metadata(test_case_id="SYSMAN_vsomeip_socket_path") + def test_sockets_path(self): + result = target.execute_command("ls /var/run/someip/vsomeip*") + assert_process_returncode(0, result, "No vsomeip sockets found") diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_system_tests.py b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_system_tests.py new file mode 100644 index 00000000000..1768a678505 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/bat_tests/vsomeip_system_tests.py @@ -0,0 +1,60 @@ +# Copyright (C) 2023. BMW Car IT GmbH. All rights reserved. +import json +import os + +from mtee.testing.support.target_share import TargetShare +from mtee.testing.tools import assert_process_returncode, metadata +from mtee.testing.test_environment import require_environment, require_environment_setup +from mtee.testing.test_environment import TEST_ENVIRONMENT as te +from mtee.testing.support.set_test_description import set_description + + +required_target_packages = ["vsomeip-systemtests-targetfiles"] + +# test needs a target for execution +target = TargetShare().target + +# include text file with tests to be excluded +with open('/tests/vsomeip/systemtests/excluded_tests.txt', 'r') as file: + excluded_tests = [] + for test in file: + test = test.strip() + excluded_tests.append(test) + + +@metadata(testsuite=["BAT", "domain", "regression"], + component="vsomeip", + domain="SYSINFRA", + duration="short", + priority=1, + image=["APPL"], + teststage="system", + testlevel="ENG_07", + traceability={ + "MGU": { + "FEATURE": ["HLF - SUC | Some/IP Communication", ], + "MGUJIRA": ["MGUSIN-11117", "MGUSIN-1442", ], + }, + }, + ) + +class TestTargetVSomeIP(object): + + @classmethod + def setup_class(cls): + cls.deploy_dir = target.targetfiles_path(__file__) + + @require_environment(te.target.simulator) + def run_tests(self): + with open('/tests/vsomeip/systemtests/test-metadata.json', 'r') as file: + for test_case in json.load(file): + + if test_case['name'] not in excluded_tests: + def execute_tests_wrapper(test): + result = target.execute_command( + args='./' + ' '.join(test['command']), cwd=self.deploy_dir, environment={**test['environment'], 'USE_DOCKER' : '1'}, timeout=120) + assert_process_returncode( + 0, result, "Executing {} failed. {}".format(test['name'], result)) + + set_description(execute_tests_wrapper, test_case['name']) + yield execute_tests_wrapper, test_case diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/CMakeLists.txt new file mode 100644 index 00000000000..e223c5ec57d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project ("benchmark_tests_bin" LANGUAGES CXX) + +file (GLOB SRCS main.cpp **/*.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable (${PROJECT_NAME} ${SRCS} ) +target_link_libraries ( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + Threads::Threads + ${Boost_LIBRARIES} + ${DL_LIBRARY} + benchmark::benchmark + gtest + vsomeip_utilities +) + +add_dependencies(build_benchmark_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/main.cpp new file mode 100644 index 00000000000..d859055f69b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/main.cpp @@ -0,0 +1,8 @@ +// Copyright (C) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_credentials.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_credentials.cpp new file mode 100644 index 00000000000..0c60fb43fff --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_credentials.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace { + vsomeip_v3::client_t client = 1; + vsomeip_v3::uid_t invalid_uid = 1; + vsomeip_v3::uid_t valid_uid = 4004201; + vsomeip_v3::gid_t invalid_gid = 1; + vsomeip_v3::gid_t valid_gid = 4004200; + vsomeip_sec_ip_addr_t host_address = 0; +} + +static void BM_check_credentials_policies_not_loaded(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + // create security clients + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + its_manager->check_credentials(client, &its_sec_client_invalid); +} + +static void BM_check_credentials_policies_loaded_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // create security clients + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + its_manager->check_credentials(client, &its_sec_client_invalid); +} + +static void BM_check_credentials_policies_loaded_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + + for (auto _ : state) + its_manager->check_credentials(client, &its_sec_client_valid); +} + +static void BM_check_credentials_policies_loaded_audit_mode_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // create security clients + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + its_manager->check_credentials(client, &its_sec_client_invalid); +} + +static void BM_check_credentials_policies_loaded_audit_mode_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + + for (auto _ : state) + its_manager->check_credentials(client, &its_sec_client_valid); +} + +BENCHMARK(BM_check_credentials_policies_not_loaded); +BENCHMARK(BM_check_credentials_policies_loaded_invalid_values); +BENCHMARK(BM_check_credentials_policies_loaded_valid_values); +BENCHMARK(BM_check_credentials_policies_loaded_audit_mode_invalid_values); +BENCHMARK(BM_check_credentials_policies_loaded_audit_mode_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_routing_credentials.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_routing_credentials.cpp new file mode 100644 index 00000000000..c24ca3e607f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_check_routing_credentials.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace{ +vsomeip_v3::uid_t invalid_uid = 1; +vsomeip_v3::uid_t valid_uid = 4003017; +vsomeip_v3::gid_t invalid_gid = 1; +vsomeip_v3::gid_t valid_gid = 5002; +vsomeip_sec_ip_addr_t host_address = 0; +} + +static void BM_check_routing_credentials_policies_not_loaded(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + security->check_routing_credentials(&its_sec_client_invalid); +} + +static void BM_check_routing_credentials_policies_loaded_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) + security->check_routing_credentials(&its_sec_client_invalid); +} + +static void BM_check_routing_credentials_policies_loaded_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) + security->check_routing_credentials(&its_sec_client_valid); +} + +static void BM_check_routing_credentials_policies_loaded_lazy_load_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + security->load(e, true); + } + + for (auto _ : state) + security->check_routing_credentials(&its_sec_client_invalid); +} + +static void BM_check_routing_credentials_policies_loaded_lazy_load_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + security->load(e, true); + } + + for (auto _ : state) + security->check_routing_credentials(&its_sec_client_valid); +} + +BENCHMARK(BM_check_routing_credentials_policies_not_loaded); +BENCHMARK(BM_check_routing_credentials_policies_loaded_invalid_values); +BENCHMARK(BM_check_routing_credentials_policies_loaded_valid_values); +BENCHMARK(BM_check_routing_credentials_policies_loaded_lazy_load_invalid_values); +BENCHMARK(BM_check_routing_credentials_policies_loaded_lazy_load_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_client_to_sec_client_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_client_to_sec_client_mapping.cpp new file mode 100644 index 00000000000..f77715e967f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_client_to_sec_client_mapping.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace{ +vsomeip_v3::client_t client = 10; +vsomeip_v3::client_t alternate_client = 11; +vsomeip_v3::uid_t uid_1 = 4003030; +vsomeip_v3::gid_t gid_1 = 4003032; +vsomeip_v3::uid_t uid_2 = 1; +vsomeip_v3::gid_t gid_2 = 1; +vsomeip_v3::uid_t uid_3 = 2; +vsomeip_v3::gid_t gid_3 = 2; +vsomeip_sec_ip_addr_t host_address = 0; +} + +static void BM_get_client_to_sec_client_mapping_valid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid_1 = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_2 = utility::create_uds_client(uid_2, gid_2, host_address); + + // add client and security client mappings + security->store_client_to_sec_client_mapping(client, &its_sec_client_uid_gid_1); + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(client, its_sec_client_uid_gid_2); + } + + vsomeip_sec_client_t its_sec_client_uid_gid_3 = utility::create_uds_client(uid_3, gid_3, host_address); + + // add alternate client and security client + security->store_client_to_sec_client_mapping(alternate_client, &its_sec_client_uid_gid_1); + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(alternate_client, its_sec_client_uid_gid_3); + } +} + +static void BM_get_client_to_sec_client_mapping_invalid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid_1 = utility::create_uds_client(uid_1, gid_1, host_address); + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(client, its_sec_client_uid_gid_1); + } + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(alternate_client, its_sec_client_uid_gid_1); + } +} + +BENCHMARK(BM_get_client_to_sec_client_mapping_valid_values); +BENCHMARK(BM_get_client_to_sec_client_mapping_invalid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_clients.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_clients.cpp new file mode 100644 index 00000000000..21c07a48a80 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_clients.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace{ +std::unordered_set<vsomeip_v3::client_t> clients; +std::unordered_set<vsomeip_v3::client_t> local_clients; +vsomeip_v3::client_t client_1 = 10; +vsomeip_v3::client_t client_2 = 11; +vsomeip_v3::client_t client_3 = 12; +vsomeip_v3::uid_t uid = 4003030; +vsomeip_v3::gid_t gid = 4003032; +vsomeip_sec_ip_addr_t host_address = 0; +} + +static void BM_get_clients(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid = utility::create_uds_client(uid, gid, host_address); + + // Loop to do the benchmark test the get with an empty clients list. + for (auto _ : state) { + security->get_clients(uid, gid, clients); + } + + local_clients.insert(client_1); + security->store_client_to_sec_client_mapping(client_1, &its_sec_client_uid_gid); + + // Loop to do the benchmark test the get with 1 client on the list + for (auto _ : state) { + security->get_clients(uid, gid, clients); + } + + // Repeat with two more clients. + security->store_client_to_sec_client_mapping(client_2, &its_sec_client_uid_gid); + security->store_client_to_sec_client_mapping(client_3, &its_sec_client_uid_gid); + + local_clients.insert(client_2); + local_clients.insert(client_3); + + //Loop to do the benchmark test the get with 3 clients on the list + for (auto _ : state) { + security->get_clients(uid, gid, clients); + } +} + +BENCHMARK(BM_get_clients); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_sec_client_to_clients_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_sec_client_to_clients_mapping.cpp new file mode 100644 index 00000000000..c8f2c42c448 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_get_sec_client_to_clients_mapping.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace{ +vsomeip_v3::client_t client = 10; +vsomeip_v3::uid_t uid_1 = 4003030; +vsomeip_v3::gid_t gid_1 = 4003032; +vsomeip_v3::uid_t uid_2 = 1; +vsomeip_v3::gid_t gid_2 = 1; +vsomeip_sec_ip_addr_t host_address = 0; +} + +static void BM_get_sec_client_to_clients_mapping_valid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_alternate = utility::create_uds_client(uid_2, gid_2, host_address); + + // Add client and uid_gid mappings. + security->store_sec_client_to_client_mapping(&its_sec_client_uid_gid, client); + + std::set<vsomeip_v3::client_t> clients_1; + for (auto _ : state) { + security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid, clients_1); + } + + // Add alternate client and uid_gid mappings. + security->store_sec_client_to_client_mapping(&its_sec_client_uid_gid_alternate, client); + + std::set<vsomeip_v3::client_t> clients_2; + for (auto _ : state) { + security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid_alternate, clients_2); + } +} + +static void BM_get_sec_client_to_clients_mapping_invalid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_alternate = utility::create_uds_client(uid_2, gid_2, host_address); + + std::set<vsomeip_v3::client_t> clients; + for (auto _ : state) { + security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid, clients); + } + + for (auto _ : state) { + security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid_alternate, clients); + } +} + +BENCHMARK(BM_get_sec_client_to_clients_mapping_valid_values); +BENCHMARK(BM_get_sec_client_to_clients_mapping_invalid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_client_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_client_allowed.cpp new file mode 100644 index 00000000000..c33c2c28de5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_client_allowed.cpp @@ -0,0 +1,201 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace { + vsomeip_v3::client_t client = 1; + + vsomeip_v3::uid_t uid_1 = 4003031; + vsomeip_v3::gid_t gid_1 = 4003031; + vsomeip_sec_ip_addr_t host_address = 0; + vsomeip_v3::service_t service_1 = 0xf913; + + vsomeip_v3::instance_t instance = 0x03; + vsomeip_v3::method_t method = 0x04; + + vsomeip_v3::gid_t invalid_uid = 1; + vsomeip_v3::gid_t invalid_gid = 1; + + vsomeip_v3::gid_t deny_uid = 9999; + vsomeip_v3::gid_t deny_gid = 9999; + vsomeip_v3::service_t deny_service = 0x40; +} + +static void BM_is_client_allowed_policies_not_loaded(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + { + its_manager->is_client_allowed(&its_sec_client_invalid, service_1, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client, service_1, instance, method); + } +} + +static void BM_is_client_allowed_cache_policies_loaded(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + + its_manager->is_client_allowed(&its_sec_client, service_1, instance, method); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client, service_1, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client_invalid, service_1, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_deny_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client_deny, deny_service, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_audit_mode_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client, client, service_1, instance, method); + } +} + +static void BM_is_client_allowed_cache_policies_loaded_audit_mode(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + + its_manager->is_client_allowed(&its_sec_client, service_1, instance, method); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client, service_1, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_audit_mode_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client_invalid, service_1, instance, method); + } +} + +static void BM_is_client_allowed_policies_loaded_audit_mode_deny_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + for (auto _ : state) { + its_manager->is_client_allowed(&its_sec_client_deny, deny_service, instance, method); + } +} + +BENCHMARK(BM_is_client_allowed_policies_not_loaded); +BENCHMARK(BM_is_client_allowed_policies_loaded_valid_values); +BENCHMARK(BM_is_client_allowed_cache_policies_loaded); +BENCHMARK(BM_is_client_allowed_policies_loaded_invalid_values); +BENCHMARK(BM_is_client_allowed_policies_loaded_deny_valid_values); +BENCHMARK(BM_is_client_allowed_policies_loaded_audit_mode_valid_values); +BENCHMARK(BM_is_client_allowed_cache_policies_loaded_audit_mode); +BENCHMARK(BM_is_client_allowed_policies_loaded_audit_mode_invalid_values); +BENCHMARK(BM_is_client_allowed_policies_loaded_audit_mode_deny_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_offer_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_offer_allowed.cpp new file mode 100644 index 00000000000..36718ae678a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_offer_allowed.cpp @@ -0,0 +1,168 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace { + +vsomeip_v3::uid_t uid_1 = 4003016; +vsomeip_v3::gid_t gid_1 = 4003016; +vsomeip_sec_ip_addr_t host_address = 0; +vsomeip_v3::service_t service_1 = 0xf8c2; + +vsomeip_v3::service_t deny_service = 0x40; + +vsomeip_v3::instance_t instance = 0x03; + +vsomeip_v3::uid_t invalid_uid = 1; +vsomeip_v3::gid_t invalid_gid = 1; + +vsomeip_v3::gid_t deny_uid = 9000; +vsomeip_v3::gid_t deny_gid = 9000; +} + +static void BM_is_offer_allowed_policies_not_loaded(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (auto _ : state) + { + security->is_offer_allowed(&its_sec_client_invalid, service_1, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(uid_1, gid_1, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_valid, service_1, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_invalid, service_1, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_deny_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_deny, deny_service, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_audit_mode_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(uid_1, gid_1, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_valid, service_1, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_audit_mode_invalid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_invalid, service_1, instance); + } +} + +static void BM_is_offer_allowed_policies_loaded_audit_mode_deny_valid_values(benchmark::State& state) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + utility::force_check_credentials(policy_elements, "false"); + + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + for (const auto& e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) { + security->is_offer_allowed(&its_sec_client_deny, deny_service, instance); + } +} + +BENCHMARK(BM_is_offer_allowed_policies_not_loaded); +BENCHMARK(BM_is_offer_allowed_policies_loaded_valid_values); +BENCHMARK(BM_is_offer_allowed_policies_loaded_invalid_values); +BENCHMARK(BM_is_offer_allowed_policies_loaded_deny_valid_values); +BENCHMARK(BM_is_offer_allowed_policies_loaded_audit_mode_valid_values); +BENCHMARK(BM_is_offer_allowed_policies_loaded_audit_mode_invalid_values); +BENCHMARK(BM_is_offer_allowed_policies_loaded_audit_mode_deny_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_policy_update_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_policy_update_allowed.cpp new file mode 100644 index 00000000000..c4bc047aaed --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_is_policy_update_allowed.cpp @@ -0,0 +1,358 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; + +vsomeip_v3::uid_t valid_uid { 0 }; +vsomeip_v3::uid_t invalid_uid { 1234567 }; + +vsomeip_v3::gid_t valid_gid { 0 }; + +vsomeip_v3::service_t valid_service { 0xf913 }; +vsomeip_v3::service_t invalid_service { 0x41 }; +} + +static void BM_is_policy_update_allowed_valid_uid_no_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + for (auto _ : state) { + security->is_policy_update_allowed(valid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_invalid_uid_no_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + for (auto _ : state) { + security->is_policy_update_allowed(invalid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_valid_uid_valid_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map< + vsomeip::instance_t, + boost::icl::interval_set<vsomeip::method_t> + >its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + valid_service, valid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + for (auto _ : state) { + security->is_policy_update_allowed(valid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_invalid_uid_valid_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, boost::icl::interval_set<vsomeip::method_t>> + its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + valid_service, valid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + for (auto _ : state) { + security->is_policy_update_allowed(invalid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_valid_uid_invalid_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map< + vsomeip::instance_t, + boost::icl::interval_set<vsomeip::method_t> + >its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + invalid_service, invalid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + for (auto _ : state) { + security->is_policy_update_allowed(valid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_invalid_uid_invalid_requests(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map< + vsomeip::instance_t, + boost::icl::interval_set<vsomeip::method_t> + >its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + invalid_service, invalid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + for (auto _ : state) { + security->is_policy_update_allowed(invalid_uid, policy); + } +} + +static void BM_is_policy_update_allowed_invalid_uid_ignore_whitelist(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { false }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + for (auto _ : state) { + security->is_policy_update_allowed(invalid_uid, policy); + } +} + +static void +BM_is_policy_update_allowed_valid_uid_invalid_request_ignore_whitelist(benchmark::State &state) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + const bool check_whitelist { false }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map< + vsomeip::instance_t, + boost::icl::interval_set<vsomeip::method_t> + >its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + invalid_service, invalid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + for (auto _ : state) { + security->is_policy_update_allowed(valid_uid, policy); + } +} + +BENCHMARK(BM_is_policy_update_allowed_valid_uid_no_requests); +BENCHMARK(BM_is_policy_update_allowed_invalid_uid_no_requests); +BENCHMARK(BM_is_policy_update_allowed_valid_uid_valid_requests); +BENCHMARK(BM_is_policy_update_allowed_invalid_uid_valid_requests); +BENCHMARK(BM_is_policy_update_allowed_valid_uid_invalid_requests); +BENCHMARK(BM_is_policy_update_allowed_invalid_uid_invalid_requests); +BENCHMARK(BM_is_policy_update_allowed_invalid_uid_ignore_whitelist); +BENCHMARK(BM_is_policy_update_allowed_valid_uid_invalid_request_ignore_whitelist); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load.cpp new file mode 100644 index 00000000000..be53d023a58 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace +{ + std::string configuration_file{"/vsomeip/vsomeip_policy_extensions.json"}; // set configuration file policy extension +} + +static void BM_configuration_element(benchmark::State &state) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Set element + std::vector<vsomeip_v3::configuration_element> full_element = {}; + + // After load try again and check size + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), + full_element, its_failed); + + // Load element and force lazy load = false + for (auto _ : state) + { + security->load(full_element.at(0), false); + } +} + +static void BM_lazy_load(benchmark::State &state) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Set element and lazy load = true + std::vector<vsomeip_v3::configuration_element> element = {}; + const bool lazy_load = true; + + // Load + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), + element, its_failed); + + for (auto _ : state) + { + security->load(element.at(0), lazy_load); + } +} + +BENCHMARK(BM_configuration_element); +BENCHMARK(BM_lazy_load); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_policies.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_policies.cpp new file mode 100644 index 00000000000..e69863c4d92 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_policies.cpp @@ -0,0 +1,98 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> +#include <common/utility.hpp> +#include <benchmark/benchmark.h> + +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; +} + +// Since this set of tests check a private method, there is the need to indirectly change the +// parameters used by load_policies, and check its changes using other methods. +// The remove_security_policy method checks if there is any loaded policy. +// The is_audit method checks the check_credentials value. +// No test was created for allow_remote_clients because it was inacessible. + +static void BM_load_policies_loaded_policies(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Using load function to indirectly call load_policies. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_policies_no_policies(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Remove all the policies from the file. + policy_elements.at(0).tree_.get_child("security").erase("policies"); + + // Using load function to indirectly call load_policies. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_policies_check_credentials_true(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies without the check credentials value set. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the check credentials value as false. + bool check_credentials_value {true}; + policy_elements.at(0).tree_.add<bool>("security.check_credentials", check_credentials_value); + + // Using load function to indirectly call load_policies. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_policies_check_credentials_false(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies without the check credentials value set. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the check credentials value as false. + bool check_credentials_value {false}; + policy_elements.at(0).tree_.add<bool>("security.check_credentials", check_credentials_value); + + // Using load function to indirectly call load_policies. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +BENCHMARK(BM_load_policies_loaded_policies); +BENCHMARK(BM_load_policies_no_policies); +BENCHMARK(BM_load_policies_check_credentials_true); +BENCHMARK(BM_load_policies_check_credentials_false); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_policy_extensions.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_policy_extensions.cpp new file mode 100644 index 00000000000..38f62caa02d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_policy_extensions.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +// create valid and invalid user credentials +namespace +{ + std::string configuration_file{ + "/vsomeip/vsomeip_policy_extensions.json"}; // set configuration file policy + +} // namespace + +static void BM_configuration_element(benchmark::State &state) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // set element + std::vector<vsomeip_v3::configuration_element> element; + std::vector<vsomeip_v3::configuration_element> full_element; + + // After load try again and check size + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data( + utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + full_element, its_failed); + + // load each e into policy_elements + for (const auto &e : full_element) + { + security->load(e, false); // for each e in policy_elements vector load e + } + + // force lazy load = false + for (auto _ : state) + { + security->load(full_element.at(0), false); + } +} + +static void BM_is_policy_extension_loaded(benchmark::State &state) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> policy_elements; + + // Force Load of policies. + std::set<std::string> its_failed; + std::set<std::string> input{utility::get_policies_path() + + configuration_file}; + utility::read_data(input, policy_elements, its_failed); + + // Load policies. + security->load(policy_elements.at(0)); + + // Check JSON container string. + std::string policy_extension_container{"android-rse"}; + + // Set extension as loaded. + bool loaded_extension = true; + + for (auto _ : state) + { + security->set_is_policy_extension_loaded(policy_extension_container, loaded_extension); + } +} + +static void BM_is_policy_extension_not_loaded(benchmark::State &state) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> policy_elements; + + // Force Load of policies. + std::set<std::string> its_failed; + std::set<std::string> input{utility::get_policies_path() + + configuration_file}; + utility::read_data(input, policy_elements, its_failed); + + // Load policies. + security->load(policy_elements.at(0)); + + // Check JSON container string. + std::string policy_extension_container{"android-rse"}; + + // Set extension NOT loaded. + bool loaded_extension = false; + + for (auto _ : state) + { + security->set_is_policy_extension_loaded(policy_extension_container, loaded_extension); + } +} + +static void BM_is_policy_extension_not_found(benchmark::State &state) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // set element + std::vector<vsomeip_v3::configuration_element> policy_elements; + + for (auto _ : state) + { + security->is_policy_extension_loaded(""); + } +} + +BENCHMARK(BM_configuration_element); +BENCHMARK(BM_is_policy_extension_loaded); +BENCHMARK(BM_is_policy_extension_not_loaded); +BENCHMARK(BM_is_policy_extension_not_found); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_update_whitelist.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_update_whitelist.cpp new file mode 100644 index 00000000000..2ec4a1e2e1c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_load_security_update_whitelist.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> +#include <common/utility.hpp> +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; +} + +// Since this set of tests check a private method, there is the need to indirectly change the +// parameters used by load_security_update_whitelist, and check its changes using other methods. +// The is_policy_removal_allowed method checks if a selected uid is present in the whitelist. +// The is_policy_update_allowed method checks if a selected service_id is present in the whitelist. + +static void BM_load_security_update_whitelist_check_no_uids_loaded(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + std::vector<vsomeip_v3::uid_t> user_ids; + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with an empty list of user uids. + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_security_update_whitelist_check_uids_loaded(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with a list of uids loaded + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_security_update_whitelist_check_no_service_ids_loaded(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies with an empty service id vector. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + std::vector<vsomeip_v3::service_t> services; + + // Add a security whitelist with an empty list of user uids. + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_security_update_whitelist_check_service_ids_loaded(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with list of service ids loaded. + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +static void BM_load_security_update_whitelist_check_whitelist_disabled(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with check_whitelist disabled + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, false); + + // Using load function to indirectly call load_security_update_whitelist. + for (auto _ : state) { + security->load(policy_elements.at(0)); + } +} + +BENCHMARK(BM_load_security_update_whitelist_check_no_uids_loaded); +BENCHMARK(BM_load_security_update_whitelist_check_no_service_ids_loaded); +BENCHMARK(BM_load_security_update_whitelist_check_uids_loaded); +BENCHMARK(BM_load_security_update_whitelist_check_service_ids_loaded); +BENCHMARK(BM_load_security_update_whitelist_check_whitelist_disabled); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_client_to_sec_client_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_client_to_sec_client_mapping.cpp new file mode 100644 index 00000000000..7b70095e69b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_client_to_sec_client_mapping.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace{ +vsomeip_v3::client_t client = 10; +vsomeip_v3::uid_t uid = 4003030; +vsomeip_v3::gid_t gid = 4003032; +vsomeip_sec_ip_addr_t host_address = 0; + +std::pair<uint32_t, uint32_t> client_uid_gid{uid, gid}; +} + +static void BM_remove_client_to_sec_client_mapping_invalid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid, gid, host_address); + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(client, its_sec_client); + } + + for (auto _ : state) { + security->remove_client_to_sec_client_mapping(client); + } +} + +static void BM_remove_client_to_sec_client_mapping_valid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid, gid, host_address); + + security->store_client_to_sec_client_mapping(client, &its_sec_client); + security->store_sec_client_to_client_mapping(&its_sec_client, client); + + for (auto _ : state) { + security->get_client_to_sec_client_mapping(client, its_sec_client); + } + + for (auto _ : state) { + security->remove_client_to_sec_client_mapping(client); + } +} + +BENCHMARK(BM_remove_client_to_sec_client_mapping_invalid_values); +BENCHMARK(BM_remove_client_to_sec_client_mapping_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_security_policy.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_security_policy.cpp new file mode 100644 index 00000000000..2fa88bbc793 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/benchmark_tests/security_tests/bm_remove_security_policy.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <benchmark/benchmark.h> + +#include <common/utility.hpp> + +namespace +{ + vsomeip_v3::uid_t invalid_uid = 1; + vsomeip_v3::uid_t valid_uid = 4002200; + vsomeip_v3::gid_t invalid_gid = 1; + vsomeip_v3::gid_t valid_gid = 4003014; +} + +static void BM_remove_security_policy_policies_not_loaded(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + for (auto _ : state) + security->remove_security_policy(invalid_uid, invalid_gid); +} + +static void BM_remove_security_policy_policies_loaded_invalid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + policy_elements, its_failed); + for (const auto &e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) + security->remove_security_policy(invalid_uid, invalid_gid); +} + +static void BM_remove_security_policy_policies_loaded_valid_values(benchmark::State &state) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + policy_elements, its_failed); + for (const auto &e : policy_elements) { + security->load(e, false); + } + + for (auto _ : state) + security->remove_security_policy(valid_uid, valid_gid); +} + +BENCHMARK(BM_remove_security_policy_policies_not_loaded); +BENCHMARK(BM_remove_security_policy_policies_loaded_invalid_values); +BENCHMARK(BM_remove_security_policy_policies_loaded_valid_values); diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/common/CMakeLists.txt new file mode 100644 index 00000000000..f74f17f354e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project (vsomeip_utilities) + +# ---------------------------------------------------------------------------- +# Include all source files (cpp/hpp) +# ---------------------------------------------------------------------------- +file (GLOB SRC src/*.cpp) +file (GLOB INC include/common/*.hpp, include/common/vsomeip_app_utilities/*.hpp) + +# ---------------------------------------------------------------------------- +# Declare the library +# ---------------------------------------------------------------------------- +add_library ( + ${PROJECT_NAME} SHARED + ${SRC} + ${INC} +) + +TARGET_LINK_LIBRARIES ( + ${PROJECT_NAME} + PUBLIC + ${VSOMEIP_NAME} + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} +) + +# ---------------------------------------------------------------------------- +# Specify here the include directories exported +# by this library +# ---------------------------------------------------------------------------- +target_include_directories ( + ${PROJECT_NAME} + PUBLIC include + PRIVATE src +) + +if (MSVC) + set_target_properties(${PROJECT_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif () diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/0_0/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/0_0/vsomeip_security.json new file mode 100644 index 00000000000..ab1b06b8b0e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/0_0/vsomeip_security.json @@ -0,0 +1,255 @@ +{ + "security": { + "policies": [ + { + "credentials": { + "gid": "0", + "uid": "0" + }, + "deny": {} + }, + { + "deny": { + "requests": [ + { + "instance": "any", + "service": "0x40" + } + ] + }, + "credentials": { + "gid": "9999", + "uid": "9999" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "0" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91b" + }, + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4002200", + "uid": "4002200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003014", + "uid": "4003014" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "4003015" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "5004", + "uid": "4003021" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91f" + }, + { + "instance": "any", + "service": "0xf8c7" + } + ] + }, + "credentials": { + "gid": "4003024", + "uid": "4003024" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003025", + "uid": "4003025" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003026", + "uid": "4003026" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91f" + } + ] + }, + "credentials": { + "gid": "4003029", + "uid": "4003029" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf913" + } + ] + }, + "credentials": { + "gid": "4003031", + "uid": "4003031" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xb025" + }, + { + "instance": "any", + "service": "0xb024" + }, + { + "instance": "any", + "service": "0xb021" + } + ] + }, + "credentials": { + "gid": "4004200", + "uid": "4004201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91f" + } + ] + }, + "credentials": { + "gid": "4013201", + "uid": "4013201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91f" + } + ] + }, + "credentials": { + "gid": "4013210", + "uid": "4013210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91b" + } + ] + }, + "credentials": { + "gid": "4017205", + "uid": "4017205" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4002200", + "4003014" + ], + "uid": [ + "4002200", + "4003014" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002200_4002200/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002200_4002200/vsomeip_security.json new file mode 100644 index 00000000000..1fb34776992 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002200_4002200/vsomeip_security.json @@ -0,0 +1,1556 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8ac" + }, + { + "instance": "any", + "service": "0x102d" + }, + { + "instance": "any", + "service": "0x102e" + }, + { + "instance": "any", + "service": "0xf8a5" + }, + { + "instance": "any", + "service": "0xf8a7" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0x1023" + }, + { + "instance": "any", + "service": "0xf8aa" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0x1002" + }, + { + "instance": "any", + "service": "0xf8ab" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ], + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xfea8" + }, + { + "instance": "any", + "service": "0xfe8c" + }, + { + "instance": "any", + "service": "0xf91b" + }, + { + "instance": "any", + "service": "0x101c" + }, + { + "instance": "any", + "service": "0xfe9c" + }, + { + "instance": "any", + "service": "0xb51a" + }, + { + "instance": "any", + "service": "0xfeaa" + }, + { + "instance": "any", + "service": "0xb510" + }, + { + "instance": "any", + "service": "0xfa60" + }, + { + "instance": "any", + "service": "0xf917" + }, + { + "instance": "any", + "service": "0xfeac" + }, + { + "instance": "any", + "service": "0xfe87" + }, + { + "instance": "any", + "service": "0xfe8a" + }, + { + "instance": "any", + "service": "0xfe86" + }, + { + "instance": "any", + "service": "0xfe88" + }, + { + "instance": "any", + "service": "0xfeab" + }, + { + "instance": "any", + "service": "0xfe9d" + }, + { + "instance": "any", + "service": "0xfea3" + }, + { + "instance": "any", + "service": "0xfea6" + }, + { + "instance": "any", + "service": "0xfe8e" + }, + { + "instance": "any", + "service": "0xfe9f" + }, + { + "instance": "any", + "service": "0xfe92" + }, + { + "instance": "any", + "service": "0xb519" + }, + { + "instance": "any", + "service": "0xfe8d" + }, + { + "instance": "any", + "service": "0xfe83" + }, + { + "instance": "any", + "service": "0xfeae" + }, + { + "instance": "any", + "service": "0xfe81" + }, + { + "instance": "any", + "service": "0xfe98" + }, + { + "instance": "any", + "service": "0xfe85" + }, + { + "instance": "any", + "service": "0xfea7" + }, + { + "instance": "any", + "service": "0xfea1" + }, + { + "instance": "any", + "service": "0xfead" + }, + { + "instance": "any", + "service": "0xfe93" + }, + { + "instance": "any", + "service": "0xfe8b" + }, + { + "instance": "any", + "service": "0xfea5" + }, + { + "instance": "any", + "service": "0x1534" + }, + { + "instance": "any", + "service": "0xfeaf" + }, + { + "instance": "any", + "service": "0xf912" + }, + { + "instance": "any", + "service": "0x1506" + }, + { + "instance": "any", + "service": "0xfe90" + }, + { + "instance": "any", + "service": "0x101d" + }, + { + "instance": "any", + "service": "0xfea9" + }, + { + "instance": "any", + "service": "0xf911" + }, + { + "instance": "any", + "service": "0x1001" + }, + { + "instance": "any", + "service": "0xfe9a" + }, + { + "instance": "any", + "service": "0xfe97" + }, + { + "instance": "any", + "service": "0x9001" + }, + { + "instance": "any", + "service": "0xf913" + }, + { + "instance": "any", + "service": "0xfe9e" + }, + { + "instance": "any", + "service": "0xb513" + }, + { + "instance": "any", + "service": "0xfeb0" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + }, + { + "instance": "any", + "service": "0xfe89" + }, + { + "instance": "any", + "service": "0xfe82" + }, + { + "instance": "any", + "service": "0x1536" + }, + { + "instance": "any", + "service": "0x1531" + }, + { + "instance": "any", + "service": "0xfea4" + }, + { + "instance": "any", + "service": "0xfe9b" + }, + { + "instance": "any", + "service": "0xfe99" + }, + { + "instance": "any", + "service": "0xfe95" + }, + { + "instance": "any", + "service": "0xfe84" + }, + { + "instance": "any", + "service": "0xfea2" + }, + { + "instance": "any", + "service": "0xfe91" + }, + { + "instance": "any", + "service": "0xfe94" + } + ] + }, + "credentials": { + "gid": "4002200", + "uid": "4002200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "0", + "uid": "0" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "0" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4003011", + "uid": "4003013" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4003014", + "uid": "4003014" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "4003015" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4003025", + "uid": "4003025" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4003026", + "uid": "4003026" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4003029", + "uid": "4003029" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4003031", + "uid": "4003031" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4003205", + "uid": "4003205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4004200", + "uid": "4004201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4005300", + "uid": "4005204" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4006200", + "uid": "4006200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4006201", + "uid": "4006201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4006202", + "uid": "4006202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4006220", + "uid": "4006220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4006221", + "uid": "4006221" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4006241", + "uid": "4006241" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4007200", + "uid": "4007200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4007210", + "uid": "4007210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4007211", + "uid": "4007211" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4007212", + "uid": "4007212" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4008300", + "uid": "4008200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4008300", + "uid": "4008203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4008303", + "uid": "4008205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4008305", + "uid": "4008207" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8aa" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4010200", + "uid": "4010200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4011201", + "uid": "4011201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8ab" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012230" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012240" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4013201", + "uid": "4013201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013202", + "uid": "4013202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + }, + { + "instance": "any", + "service": "0xf8a4" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "5501", + "uid": "4013203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "5510", + "uid": "4013206" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013209", + "uid": "4013209" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013213", + "uid": "4013213" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013214", + "uid": "4013214" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013215", + "uid": "4013215" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013217", + "uid": "4013217" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013218", + "uid": "4013218" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013219", + "uid": "4013219" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013223", + "uid": "4013223" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013225", + "uid": "4013225" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + } + ] + }, + "credentials": { + "gid": "4013229", + "uid": "4013229" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "5510", + "uid": "4013232" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4013233", + "uid": "4013233" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "4013234", + "uid": "4013234" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4013242", + "uid": "4013242" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4014201", + "uid": "4014201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a5" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a2" + } + ] + }, + "credentials": { + "gid": "4014300", + "uid": "4014300" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0x102d" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4014390", + "uid": "4014390" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4015210", + "uid": "4015210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a0" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a3" + }, + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a2" + } + ] + }, + "credentials": { + "gid": "4017201", + "uid": "4017201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4017202", + "uid": "4017202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017208", + "uid": "4017208" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017209", + "uid": "4017209" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017210", + "uid": "4017210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8ac" + }, + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017211", + "uid": "4017211" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017215", + "uid": "4017215" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4017216", + "uid": "4017216" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a2" + } + ] + }, + "credentials": { + "gid": "4017219", + "uid": "4017219" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + }, + { + "instance": "any", + "service": "0xf8a2" + } + ] + }, + "credentials": { + "gid": "4017220", + "uid": "4017220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a4" + } + ] + }, + "credentials": { + "gid": "4017221", + "uid": "4017221" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4018204", + "uid": "4018204" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4012300", + "4013225", + "4003031", + "4013201", + "4017219", + "4013202", + "4003014", + "4017221", + "4017201", + "4017211", + "4006200", + "4013213", + "4003026", + "4011201", + "4006220", + "4013218", + "4013217", + "0", + "4014300", + "4013215", + "4003019", + "4013207", + "4013211", + "4013223", + "4008303", + "4013220", + "4005300", + "4003205", + "4013219", + "4007210", + "4003024", + "4004200", + "4007234", + "4006202", + "5510", + "4013200" + ], + "uid": [ + "4013232", + "4013225", + "4003031", + "4012201", + "4013201", + "4005202", + "4017219", + "4008205", + "4013202", + "4003014", + "4017221", + "4017201", + "4004201", + "4017211", + "4006200", + "4013213", + "4003026", + "4011201", + "4006220", + "4013218", + "4013217", + "4013206", + "0", + "4014300", + "4013215", + "4003019", + "4013207", + "4013211", + "4013223", + "4013220", + "4003205", + "4013219", + "4007210", + "4012240", + "4003024", + "4007234", + "4006202", + "4013200" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002201_4002201/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002201_4002201/vsomeip_security.json new file mode 100644 index 00000000000..7e725bae945 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002201_4002201/vsomeip_security.json @@ -0,0 +1,122 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0x1501" + }, + { + "instance": "any", + "service": "0xf8a8" + } + ], + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + }, + { + "instance": "any", + "service": "0x1532" + } + ] + }, + "credentials": { + "gid": "4002201", + "uid": "4002201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a8" + } + ] + }, + "credentials": { + "gid": "4003024", + "uid": "4003024" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a8" + } + ] + }, + "credentials": { + "gid": "4004200", + "uid": "4004201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0x1501" + } + ] + }, + "credentials": { + "gid": "4006202", + "uid": "4006202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a8" + } + ] + }, + "credentials": { + "gid": "4011201", + "uid": "4011201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a8" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016203" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4003014" + ], + "uid": [ + "4003014" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002205_4002205/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002205_4002205/vsomeip_security.json new file mode 100644 index 00000000000..0d70132e89a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4002205_4002205/vsomeip_security.json @@ -0,0 +1,54 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf8a6" + } + ], + "requests": [ + { + "instance": "any", + "service": "0xf8c1" + } + ] + }, + "credentials": { + "gid": "4002205", + "uid": "4002205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8a6" + } + ] + }, + "credentials": { + "gid": "4014300", + "uid": "4014300" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4003024" + ], + "uid": [ + "4003024" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003013_4003011/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003013_4003011/vsomeip_security.json new file mode 100644 index 00000000000..1534a93b2fc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003013_4003011/vsomeip_security.json @@ -0,0 +1,64 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf8d0" + } + ], + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf8a4" + }, + { + "instance": "any", + "service": "0xf8a1" + } + ] + }, + "credentials": { + "gid": "4003011", + "uid": "4003013" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8d0" + } + ] + }, + "credentials": { + "gid": "4003025", + "uid": "4003025" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4002200", + "4003014" + ], + "uid": [ + "4002200", + "4003014" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003014_4003014/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003014_4003014/vsomeip_security.json new file mode 100644 index 00000000000..06af6565ae9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003014_4003014/vsomeip_security.json @@ -0,0 +1,1306 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xb067" + }, + { + "instance": "any", + "service": "0xf8c4" + }, + { + "instance": "any", + "service": "0xfe85" + }, + { + "instance": "any", + "service": "0xb0a7" + }, + { + "instance": "any", + "service": "0xb0a8" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ], + "requests": [ + { + "instance": "any", + "service": "0x1531" + }, + { + "instance": "any", + "service": "0xb519" + }, + { + "instance": "any", + "service": "0xf8c2" + }, + { + "instance": "any", + "service": "0x1024" + }, + { + "instance": "any", + "service": "0x1397" + }, + { + "instance": "any", + "service": "0xb504" + }, + { + "instance": "any", + "service": "0xf8a0" + }, + { + "instance": "any", + "service": "0xf913" + }, + { + "instance": "any", + "service": "0xb020" + }, + { + "instance": "any", + "service": "0xb0a7" + }, + { + "instance": "any", + "service": "0xf8a2" + }, + { + "instance": "any", + "service": "0xb0a8" + }, + { + "instance": "any", + "service": "0xf918" + }, + { + "instance": "any", + "service": "0x1032" + }, + { + "instance": "any", + "service": "0xf8a4" + }, + { + "instance": "any", + "service": "0x1533" + } + ] + }, + "credentials": { + "gid": "4003014", + "uid": "4003014" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "0", + "uid": "0" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8c4" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "0" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4004200", + "uid": "1041" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xfe85" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4002200", + "uid": "4002200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4002201", + "uid": "4002201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003011", + "uid": "4003013" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8c4" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "4003015" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003019", + "uid": "4003019" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003022", + "uid": "4003022" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003024", + "uid": "4003024" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8c4" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4003025", + "uid": "4003025" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003026", + "uid": "4003026" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003027", + "uid": "4003027" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003028", + "uid": "4003028" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4003031", + "uid": "4003031" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003036", + "uid": "4003036" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003203", + "uid": "4003203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003205", + "uid": "4003205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4003207", + "uid": "4003207" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4004200", + "uid": "4004201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4006200", + "uid": "4006200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + } + ] + }, + "credentials": { + "gid": "4006202", + "uid": "4006202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4006220", + "uid": "4006220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4006221", + "uid": "4006221" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4006222", + "uid": "4006222" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + } + ] + }, + "credentials": { + "gid": "4006241", + "uid": "4006241" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4007200", + "uid": "4007200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xb0a7" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4007210", + "uid": "4007210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xb0a7" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4007211", + "uid": "4007211" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4007234", + "uid": "4007234" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4008300", + "uid": "4008202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4008300", + "uid": "4008204" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xb067" + }, + { + "instance": "any", + "service": "0xb0a7" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4010200", + "uid": "4010200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4011201", + "uid": "4011201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012202" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012230" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012232" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4012300", + "uid": "4012240" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013200", + "uid": "4013200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013201", + "uid": "4013201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "5510", + "uid": "4013206" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013211", + "uid": "4013211" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013212", + "uid": "4013212" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013213", + "uid": "4013213" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4013214", + "uid": "4013214" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4013218", + "uid": "4013218" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4013219", + "uid": "4013219" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xb067" + } + ] + }, + "credentials": { + "gid": "4013220", + "uid": "4013220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "5510", + "uid": "4013232" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4014201", + "uid": "4014201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf902" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4014300", + "uid": "4014300" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4014390", + "uid": "4014390" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4015200", + "uid": "4015200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4015201", + "uid": "4015201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016203" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016204" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "5509", + "uid": "4016205" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017200", + "uid": "4017200" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017201", + "uid": "4017201" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017208", + "uid": "4017208" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017209", + "uid": "4017209" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017210", + "uid": "4017210" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017211", + "uid": "4017211" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017215", + "uid": "4017215" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017216", + "uid": "4017216" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf91c" + }, + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017218", + "uid": "4017218" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017219", + "uid": "4017219" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017220", + "uid": "4017220" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf901" + } + ] + }, + "credentials": { + "gid": "4017221", + "uid": "4017221" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "0", + "4003016", + "4004200", + "4013207", + "4003015", + "4002200", + "4013200" + ], + "uid": [ + "0", + "4003016", + "4004201", + "4013207", + "4003015", + "4002200", + "4013200" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003015_4003015/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003015_4003015/vsomeip_security.json new file mode 100644 index 00000000000..b92ae37bcfe --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003015_4003015/vsomeip_security.json @@ -0,0 +1,82 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf918" + } + ], + "requests": [ + { + "instance": "any", + "service": "0xf8c4" + }, + { + "instance": "any", + "service": "0xf90c" + }, + { + "instance": "any", + "service": "0xf913" + }, + { + "instance": "any", + "service": "0xf901" + }, + { + "instance": "any", + "service": "0xf8a4" + }, + { + "instance": "any", + "service": "0xf902" + } + ] + }, + "credentials": { + "gid": "4003015", + "uid": "4003015" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf918" + } + ] + }, + "credentials": { + "gid": "4003014", + "uid": "4003014" + } + }, + { + "credentials": { + "allow": [ + { + "gid": [ + "4003014", + "0", + "4013207", + "4003203", + "4002200" + ], + "uid": [ + "4003014", + "0", + "4013207", + "4003203", + "4002200" + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003016_4003016/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003016_4003016/vsomeip_security.json new file mode 100644 index 00000000000..eedb1248269 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/4003016_4003016/vsomeip_security.json @@ -0,0 +1,63 @@ +{ + "security": { + "policies": [ + { + "allow": { + "offers": [ + { + "instance": "any", + "service": "0xf8c2" + } + ], + "requests": [] + }, + "credentials": { + "gid": "4003016", + "uid": "4003016" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8c2" + } + ] + }, + "credentials": { + "gid": "4003014", + "uid": "4003014" + } + }, + { + "allow": { + "requests": [ + { + "instance": "any", + "service": "0xf8c2" + } + ] + }, + "credentials": { + "gid": "4013202", + "uid": "4013202" + } + }, + { + "deny": { + "offers": [ + { + "instance": "any", + "service": "0x40" + } + ] + }, + "credentials": { + "gid": "9000", + "uid": "9000" + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_policy_extensions.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_policy_extensions.json new file mode 100644 index 00000000000..51993268d05 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_policy_extensions.json @@ -0,0 +1 @@ +{"container_policy_extensions": [{"container": "android-rse", "path": "../vsomeip_ext/android"}, {"container": "android-idc", "path": "../vsomeip_ext/android"}, {"container": "android-idc-base", "path": "../vsomeip_ext/android"}]} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_security.json b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_security.json new file mode 100644 index 00000000000..d278ea869df --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/examples_policies/vsomeip/vsomeip_security.json @@ -0,0 +1,25 @@ +{ + "routing-credentials": { + "gid": "5002", + "uid": "4003017" + }, + "security": { + "check_credentials": "true", + "policies": [ + { + "allow": {}, + "credentials": { + "gid": "5002", + "uid": "4003017" + } + }, + { + "credentials": { + "gid": "0", + "uid": "0" + }, + "deny": {} + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/test_timer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/test_timer.hpp new file mode 100644 index 00000000000..ffeb89c4a22 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/test_timer.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef TEST_TIMER_HPP +#define TEST_TIMER_HPP + +#include <chrono> + +class test_timer_t { +public: + test_timer_t(std::chrono::milliseconds target_) : + target(target_), start(std::chrono::high_resolution_clock::now()) { } + test_timer_t(std::chrono::seconds target_) : + target(std::chrono::duration_cast<std::chrono::milliseconds>(target_)), + start(std::chrono::high_resolution_clock::now()) { } + + bool has_elapsed() { + const auto current = std::chrono::high_resolution_clock::now(); + return target <= std::chrono::duration_cast<std::chrono::seconds>(current - start); + } + +private: + std::chrono::milliseconds target; + std::chrono::system_clock::time_point start; +}; + +#endif // TEST_TIMER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/utility.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/utility.hpp new file mode 100644 index 00000000000..35f6e9273ee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/utility.hpp @@ -0,0 +1,80 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/vsomeip.hpp> + +#include "../../../implementation/configuration/include/configuration_impl.hpp" +#include "../../../implementation/routing/include/routing_manager_impl.hpp" +#include "../../../implementation/security/include/policy_manager_impl.hpp" +#include "../../../implementation/configuration/include/configuration_impl.hpp" +#include "../../../implementation/utility/include/utility.hpp" + +// This is needed to silence internal warnings in boost, when e.g. including <boost/property_tree/json_parser.hpp> +#define BOOST_BIND_GLOBAL_PLACEHOLDERS + +#include <boost/filesystem.hpp> +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/json_parser.hpp> + +#include <iostream> + +class utility { +public: + static void load_policy_data(std::string _input, + std::vector<vsomeip_v3::configuration_element> &_elements, + std::set<std::string> &_failed); + + static void read_data(const std::set<std::string> &_input, + std::vector<vsomeip_v3::configuration_element> &_elements, std::set<std::string> &_failed); + + static std::set<std::string> get_all_files_in_dir(const std::string &_dir_path, + const std::vector<std::string> &_dir_skip_list); + + static std::string get_policies_path(); + + static vsomeip_sec_client_t create_uds_client(uid_t user, gid_t group, vsomeip_sec_ip_addr_t host); + + static void force_check_credentials(std::vector<vsomeip_v3::configuration_element> &_policy_elements, std::string _value); + /** + * @brief Get all of the user ids in the given policy element. + * + * @param _policy_element + * @param _out_uids + */ + static void get_policy_uids(vsomeip_v3::configuration_element &_policy_element, + std::vector<vsomeip_v3::uid_t> &_out_uids); + + /** + * @brief Get all of the services in the given policy element. + * + * @param _policy_element + * @param _out_services + */ + static void get_policy_services(vsomeip_v3::configuration_element &_policy_element, + std::vector<vsomeip_v3::service_t> &_out_services); + + /** + * @brief Add a security whitelist to the given policy element. Uses all user ids and + * services mentioned in the policy. + * + * @param _policy_element + * @param _check_whitelist + */ + static void add_security_whitelist(vsomeip_v3::configuration_element &_policy_element, + const bool _check_whitelist); + + /** + * @brief Add a security whitelist with the given ids and services to the policy element. + * + * @param _policy_element + * @param _user_ids + * @param _services + * @param _check_whitelist + */ + static void add_security_whitelist(vsomeip_v3::configuration_element &_policy_element, + const std::vector<vsomeip_v3::uid_t> &_user_ids, + const std::vector<vsomeip_v3::service_t> &_services, + const bool _check_whitelist); +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/vsomeip_app_utilities.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/vsomeip_app_utilities.hpp new file mode 100644 index 00000000000..5ad0be398c1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/include/common/vsomeip_app_utilities.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_BASE_APP +#define VSOMEIP_BASE_APP +#include <vsomeip/vsomeip.hpp> +#include <condition_variable> +#include <mutex> +#include <thread> +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef USE_DLT +#ifndef ANDROID +#include <dlt/dlt.h> +#endif +#endif + +namespace vsomeip_utilities { + +std::shared_ptr<vsomeip_v3::message> create_standard_vsip_request( + vsomeip::service_t _service, vsomeip::instance_t _instance, vsomeip_v3::method_t _method, + vsomeip_v3::interface_version_t _interface, vsomeip_v3::message_type_e _message_type); + +class base_logger +{ +public: + const char *_dlt_application_id = nullptr; + const char *_dlt_application_name = nullptr; + + base_logger(const char *dlt_application_id, const char *dlt_application_name); + + ~base_logger(); +}; + +class base_vsip_app: public base_logger +{ +protected: + std::shared_ptr<vsomeip::application> _app; + std::thread _run_thread; + + void run(); + +public: + base_vsip_app(const char *app_name_, const char *app_id_); + ~base_vsip_app(); +}; +} +#endif // VSOMEIP_BASE_APP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/utility.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/utility.cpp new file mode 100644 index 00000000000..cdf6db8a9ab --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/utility.cpp @@ -0,0 +1,233 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <common/utility.hpp> + +void +utility::load_policy_data(std::string _input, + std::vector<vsomeip_v3::configuration_element> &_elements, + std::set<std::string> &_failed) { + + boost::property_tree::ptree its_tree; + try { + boost::property_tree::json_parser::read_json(_input, its_tree); + _elements.push_back({ _input, its_tree }); + } + catch (boost::property_tree::json_parser_error &e) { + _failed.insert(_input); + } +} + +void +utility::read_data(const std::set<std::string> &_input, + std::vector<vsomeip_v3::configuration_element> &_elements, + std::set<std::string> &_failed) { + + for (auto i : _input) { + if (vsomeip_v3::utility::is_file(i)) { + load_policy_data(i, _elements, _failed); + } else if (vsomeip_v3::utility::is_folder(i)) { + std::map<std::string, bool> its_names; + boost::filesystem::path its_path(i); + for (auto j = boost::filesystem::directory_iterator(its_path); + j != boost::filesystem::directory_iterator(); + j++) { + std::string name = j->path().string() + "/vsomeip_security.json"; + if (vsomeip_v3::utility::is_file(name)) + its_names[name] = true; + } + + for (const auto& n : its_names) + load_policy_data(n.first, _elements, _failed); + } + } +} + +std::set<std::string> +utility::get_all_files_in_dir(const std::string &_dir_path, + const std::vector<std::string> &_dir_skip_list) { + + // Create a vector of string + std::set<std::string> list_of_files; + try { + // Check if given path exists and points to a directory + if (boost::filesystem::exists(_dir_path) + && boost::filesystem::is_directory(_dir_path)) { + // Create a Recursive Directory Iterator object and points to the + // starting of directory + boost::filesystem::recursive_directory_iterator iter(_dir_path); + // Create a Recursive Directory Iterator object pointing to end. + boost::filesystem::recursive_directory_iterator end; + // Iterate till end + while (iter != end) { + // Check if current entry is a directory and if exists in + // skip list + if (boost::filesystem::is_directory(iter->path()) + && (std::find(_dir_skip_list.begin(), + _dir_skip_list.end(), iter->path().filename()) + != _dir_skip_list.end())) { + // Boost Filesystem API to skip current directory iteration +#if VSOMEIP_BOOST_VERSION < 108100 + iter.no_push(); +#else + iter.disable_recursion_pending(); +#endif + } else { + // Add the name in vector + list_of_files.insert(iter->path().string()); + } + boost::system::error_code ec; + // Increment the iterator to point to next entry in recursive iteration + iter.increment(ec); + if (ec) { + std::cerr << "Error While Accessing : " << iter->path().string() << " :: " << ec.message() << '\n'; + } + } + } + } + catch (std::system_error & e) { + std::cerr << "Exception :: " << e.what(); + } + return list_of_files; +} + +std::string +utility::get_policies_path() { + + return boost::filesystem::canonical( + boost::filesystem::current_path()).string() + + "/../test/common/examples_policies"; +} + +vsomeip_sec_client_t +utility::create_uds_client(uid_t user, gid_t group, vsomeip_sec_ip_addr_t host) { + vsomeip_sec_client_t result{ user, group, host, VSOMEIP_SEC_PORT_UNUSED }; + return result; +} + +void +utility::force_check_credentials( + std::vector<vsomeip_v3::configuration_element> &_policy_elements, + std::string _value) { + + for(auto &i : _policy_elements) { + try { + boost::property_tree::ptree &security + = i.tree_.get_child("security"); + boost::property_tree::ptree &credentials + = security.get_child("check_credentials"); + if (credentials.get_value<std::string>().compare(_value)) { + security.erase("check_credentials"); + credentials.put("check_credentials", _value); + } + } + catch(...) {} + } + } + +void utility::get_policy_uids(vsomeip_v3::configuration_element &_policy_element, + std::vector<vsomeip_v3::uid_t> &_out_uids) +{ + try { + std::vector<std::string> user_ids; + auto policy_tree = _policy_element.tree_.get_child("security.policies"); + for (auto policy_node : policy_tree) { + auto optional_credential_node = + policy_node.second.get_child_optional("credentials.uid"); + if (optional_credential_node) { + auto optional_user_id = + optional_credential_node.get().get_value_optional<std::string>(); + if (optional_user_id) { + user_ids.push_back(optional_user_id.get()); + } + } + } + for (const std::string &uid_string : user_ids) { + _out_uids.push_back((vsomeip_v3::uid_t)std::strtoul(uid_string.c_str(), NULL, 0)); + } + } catch (...) { + std::cerr << "Caught exception while reading user ids in policy element \"" + << _policy_element.name_ << "\"!" << std::endl; + } +} + +void utility::get_policy_services(vsomeip_v3::configuration_element &_policy_element, + std::vector<vsomeip_v3::service_t> &_out_services) +{ + try { + std::vector<std::string> services; + auto policy_tree = _policy_element.tree_.get_child("security.policies"); + for (auto policy_node : policy_tree) { + // Get allowed request services. + auto allow_requests = policy_node.second.get_child_optional("allow.requests"); + if (allow_requests) { + for (auto &request_node : allow_requests.get()) { + auto optional_service = request_node.second.get_child("service") + .get_value_optional<std::string>(); + if (optional_service) { + services.push_back(optional_service.get()); + } + } + } + // Get denied request services. + auto deny_requests = policy_node.second.get_child_optional("deny.requests"); + if (deny_requests) { + for (auto &request_node : deny_requests.get()) { + auto optional_service = request_node.second.get_child("service") + .get_value_optional<std::string>(); + if (optional_service) { + services.push_back(optional_service.get()); + } + } + } + } + for (const std::string &service_str : services) { + _out_services.push_back( + (vsomeip_v3::service_t)std::strtoul(service_str.c_str(), NULL, 0)); + } + } catch (...) { + std::cerr << "Caught exception while reading services in policy element \"" + << _policy_element.name_ << "\"!" << std::endl; + } +} + +void utility::add_security_whitelist(vsomeip_v3::configuration_element &_policy_element, + const bool _check_whitelist) +{ + std::vector<vsomeip_v3::uid_t> user_ids; + get_policy_uids(_policy_element, user_ids); + + std::vector<vsomeip_v3::service_t> services; + get_policy_services(_policy_element, services); + + add_security_whitelist(_policy_element, user_ids, services, _check_whitelist); +} + +void utility::add_security_whitelist(vsomeip_v3::configuration_element &_policy_element, + const std::vector<vsomeip_v3::uid_t> &_user_ids, + const std::vector<vsomeip_v3::service_t> &_services, + const bool _check_whitelist) +{ + // Add the user ids to the whitelist. + boost::property_tree::ptree id_array_node; + for (auto user_id : _user_ids) { + boost::property_tree::ptree id_node; + id_node.put("", user_id); + id_array_node.push_back(std::make_pair("", id_node)); + } + _policy_element.tree_.add_child("security-update-whitelist.uids", id_array_node); + + // Add the services to the whitelist. + boost::property_tree::ptree service_array_node; + for (auto service : _services) { + boost::property_tree::ptree service_node; + service_node.put("", service); + service_array_node.push_back(std::make_pair("", service_node)); + } + _policy_element.tree_.add_child("security-update-whitelist.services", service_array_node); + + // Update the 'check_whitelist' flag. + _policy_element.tree_.add<bool>("security-update-whitelist.check-whitelist", _check_whitelist); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/vsomeip_app_utilities.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/vsomeip_app_utilities.cpp new file mode 100644 index 00000000000..f2e00106c2e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/common/src/vsomeip_app_utilities.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <common/vsomeip_app_utilities.hpp> + +namespace vsomeip_utilities { + +std::shared_ptr<vsomeip_v3::message> create_standard_vsip_request( + vsomeip::service_t _service, vsomeip::instance_t _instance, vsomeip_v3::method_t _method, + vsomeip_v3::interface_version_t _interface, vsomeip_v3::message_type_e _message_type) +{ + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(_service); + its_message->set_instance(_instance); + its_message->set_method(_method); + its_message->set_interface_version(_interface); + its_message->set_message_type(_message_type); + its_message->set_payload(its_payload); + + return its_message; +} + +base_logger::base_logger(const char *dlt_application_id, const char *dlt_application_name) + : _dlt_application_id(dlt_application_id), + _dlt_application_name(dlt_application_name) +{ +#ifdef USE_DLT +#ifndef ANDROID + DLT_REGISTER_APP(_dlt_application_id, _dlt_application_name); +#endif +#endif +} + +base_logger::~base_logger() +{ +#ifdef USE_DLT +#ifndef ANDROID + DLT_UNREGISTER_APP(); +#endif +#endif +} + +base_vsip_app::base_vsip_app(const char *app_name_, const char *app_id_) : base_logger( app_name_, app_id_) +{ + _app = vsomeip::runtime::get()->create_application(app_name_); + _app->init(); + _run_thread = std::thread(std::bind(&base_vsip_app::run, this)); +} + +void base_vsip_app::run() +{ + _app->start(); +} + +base_vsip_app::~base_vsip_app() +{ + _app->stop(); + _run_thread.join(); +} +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/CMakeLists.txt new file mode 100644 index 00000000000..2c2021fb578 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.4...3.22) + +# Workaround for version range in cmake_minimum_required() before 3.12 +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() + +project(internal_routing_disabled_acceptance_test LANGUAGES CXX) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wconversion -Wextra") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +add_executable(${PROJECT_NAME} applet.cpp client.cpp server.cpp main.cpp) +target_include_directories(${PROJECT_NAME} PRIVATE ${gtest_SOURCE_DIR}/include) +target_link_libraries(${PROJECT_NAME} PRIVATE gtest Threads::Threads vsomeip3 ${Boost_LIBRARIES}) + +if (${CMAKE_SYSTEM_NAME} MATCHES "QNX") + target_compile_definitions(${PROJECT_NAME} PRIVATE _QNX_SOURCE) +endif() + +enable_testing() +add_test(NAME ${PROJECT_NAME} COMMAND $<TARGET_FILE:${PROJECT_NAME}>) +add_dependencies(build_network_tests ${PROJECT_NAME}) +configure_file(vsomeip.json vsomeip.json COPYONLY) +set_property( + TEST ${PROJECT_NAME} + APPEND PROPERTY ENVIRONMENT + "LD_LIBRARY_PATH=$<TARGET_FILE_DIR:vsomeip3>" + "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/vsomeip.json" +) +set_property( + TEST ${PROJECT_NAME} + APPEND PROPERTY TIMEOUT + 60 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.cpp new file mode 100644 index 00000000000..d327fbdd172 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.cpp @@ -0,0 +1,56 @@ +#include "applet.hpp" + +#include <stdexcept> +#include <string> + +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/runtime.hpp> + +applet::applet(std::string_view name) + : application{vsomeip_v3::runtime::get()->create_application(std::string{name})} +{ + +} + +applet::~applet() +{ + this->application->clear_all_handler(); + this->application->stop(); + this->async_start.wait(); +} + +void +applet::init() { + + std::weak_ptr<applet> its_me = shared_from_this(); + + if(!this->application->init()) + { + using namespace std::string_literals; + throw std::runtime_error{__func__ + "(): vSomeIP application init failure"s}; + } + + this->async_start = std::async( + std::launch::async, + &vsomeip_v3::application::start, + this->application + ); + + this->application->register_state_handler( + [its_me](vsomeip_v3::state_type_e state) { + auto me = its_me.lock(); + if (me) { + switch(state) + { + case vsomeip_v3::state_type_e::ST_REGISTERED: + return me->on_state_registered(); + case vsomeip_v3::state_type_e::ST_DEREGISTERED: + return me->on_state_deregistered(); + } + } + } + ); +} + +void applet::on_state_registered() {} +void applet::on_state_deregistered() {} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.hpp new file mode 100644 index 00000000000..0d273433259 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/applet.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <future> +#include <memory> +#include <string_view> + +#include <vsomeip/application.hpp> + +struct applet : public std::enable_shared_from_this<applet> +{ +protected: + std::shared_ptr<vsomeip_v3::application> application; + + applet(std::string_view name); + virtual ~applet(); + + void init(); + +private: + std::future<void> async_start; + + virtual void on_state_registered(); + virtual void on_state_deregistered(); +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.cpp new file mode 100644 index 00000000000..afe960f573f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.cpp @@ -0,0 +1,176 @@ +#include "client.hpp" + +#include <chrono> +#include <iostream> +#include <thread> + +#include <vsomeip/constants.hpp> +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/primitive_types.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "config.hpp" + +client::client() : applet{"client"}, counter_event_received{}, counter_method_request{}, counter_method_response{} +{ +} + +void +client::init() { + applet::init(); + + std::weak_ptr<client> its_me + = std::dynamic_pointer_cast<client>(shared_from_this()); + + this->application->register_message_handler( + config::SERVICE_ID, + config::INSTANCE_ID, + vsomeip_v3::ANY_METHOD, + [its_me](const std::shared_ptr<vsomeip_v3::message>& message){ + auto me = its_me.lock(); + if (me) { + std::shared_ptr runtime = vsomeip_v3::runtime::get(); + std::shared_ptr payload = message->get_payload(); + + switch(message->get_message_type()) + { + case vsomeip_v3::message_type_e::MT_RESPONSE: + VSOMEIP_INFO << "received:\n" + << "\tservice: " << std::hex << message->get_service() << '\n' + << "\tinstance: " << std::hex << message->get_instance() << '\n' + << "\tmethod: " << std::hex << message->get_method() << '\n' + << "\tpayload: " << payload->get_data(); + me->counter_method_response++; + break; + + case vsomeip_v3::message_type_e::MT_NOTIFICATION: + VSOMEIP_INFO << "GOT NOTIFICATION"; + me->counter_event_received++; + [[fallthrough]]; + + default: + VSOMEIP_ERROR << "unhandled message type: " + << unsigned(message->get_message_type()); + } + } + } + ); + + this->application->register_availability_handler( + config::SERVICE_ID, + config::INSTANCE_ID, + [its_me](vsomeip_v3::service_t service, vsomeip_v3::instance_t instance, bool available){ + auto me = its_me.lock(); + if (me) { + VSOMEIP_INFO << __func__ << '('<< std::hex << service << ", " << std::hex + << instance << ", " << std::boolalpha << available << ")"; + + if(service != config::SERVICE_ID) + return; + if(instance != config::INSTANCE_ID) + return; + if(!available) + return; + + std::shared_ptr runtime = vsomeip_v3::runtime::get(); + + std::shared_ptr payload = runtime->create_payload(); + constexpr vsomeip_v3::byte_t str[]{"hello world"}; + payload->set_data(str, sizeof(str)); + + std::shared_ptr request = runtime->create_request(); + request->set_service(config::SERVICE_ID); + request->set_instance(config::INSTANCE_ID); + request->set_method(config::METHOD_ID); + request->set_payload(payload); + + for(int i = 0; i < 10; i++) + { + VSOMEIP_INFO << "sending: " << str; + me->application->send(request); + me->counter_method_request++; + + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + } + } + } + ); + + this->application->request_event( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID, + {config::EVENTGROUP_ID}, + vsomeip_v3::event_type_e::ET_FIELD, + vsomeip_v3::reliability_type_e::RT_UNRELIABLE + ); + + this->application->subscribe( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENTGROUP_ID + ); +} + +client::~client() +{ + this->application->unsubscribe( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENTGROUP_ID + ); + + this->application->release_event( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID + ); + + this->application->release_service( + config::SERVICE_ID, + config::INSTANCE_ID + ); + + this->application->unregister_availability_handler( + config::SERVICE_ID, + config::INSTANCE_ID + ); + + this->application->unregister_message_handler( + config::SERVICE_ID, + config::INSTANCE_ID, + vsomeip_v3::ANY_METHOD + ); +} + +std::size_t client::get_event_count() noexcept +{ + return this->counter_event_received; +} + +std::size_t client::get_method_request_count() noexcept +{ + return this->counter_method_request; +} + +std::size_t client::get_method_response_count() noexcept +{ + return this->counter_method_response; +} + +void client::on_state_registered() +{ + this->application->request_service( + config::SERVICE_ID, + config::INSTANCE_ID + ); +} + +void client::on_state_deregistered() +{ + VSOMEIP_WARNING << "Client is deregistered!!! Probably could not be registered!!!"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.hpp new file mode 100644 index 00000000000..e1f22dbe729 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/client.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <atomic> +#include <cstddef> +#include <memory> + +#include "applet.hpp" + +struct client final : applet +{ + client(); + ~client(); + + void init(); + + std::size_t get_event_count() noexcept; + std::size_t get_method_request_count() noexcept; + std::size_t get_method_response_count() noexcept; + +private: + void on_state_registered() override; + void on_state_deregistered() override; + + std::atomic_size_t counter_event_received; + std::atomic_size_t counter_method_request; + std::atomic_size_t counter_method_response; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/config.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/config.hpp new file mode 100644 index 00000000000..50dab14bf0d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/config.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include <vsomeip/primitive_types.hpp> + +namespace config +{ + constexpr vsomeip_v3::service_t SERVICE_ID = 0x2222; + constexpr vsomeip_v3::instance_t INSTANCE_ID = 0x3333; + constexpr vsomeip_v3::method_t METHOD_ID = 0x4444; + constexpr vsomeip_v3::event_t EVENT_ID = 0x5555; + constexpr vsomeip_v3::eventgroup_t EVENTGROUP_ID = 0x6666; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/main.cpp new file mode 100644 index 00000000000..270132e3c43 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/main.cpp @@ -0,0 +1,48 @@ +#include <chrono> +#include <iostream> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/internal/logger.hpp> + +#include "client.hpp" +#include "server.hpp" + +TEST(internal_routing_disabled_acceptance_test, check_connectivity) +{ + auto s = std::make_shared<server>(); + s->init(); + + auto c = std::make_shared<client>(); + c->init(); + + using namespace std::chrono_literals; + std::this_thread::sleep_for(15s); + + VSOMEIP_INFO + << "[server]\n" + << "\tevents: " << s->get_event_count() << '\n' + << "\tmethod requests: " << s->get_method_request_count() << '\n' + << "\tmethod responses: " << s->get_method_response_count(); + + VSOMEIP_INFO + << "[client]\n" + << "\tevents: " << c->get_event_count() << '\n' + << "\tmethod requests: " << c->get_method_request_count() << '\n' + << "\tmethod responses: " << c->get_method_response_count(); + + EXPECT_EQ(s->get_event_count(), 10); + EXPECT_EQ(s->get_method_request_count(), 0); + EXPECT_EQ(s->get_method_response_count(), 0); + + EXPECT_EQ(c->get_event_count(), 0); + EXPECT_EQ(c->get_method_request_count(), 0); + EXPECT_EQ(c->get_method_response_count(), 0); +} + +int main(int count, char** values) +{ + testing::InitGoogleTest(&count, values); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.cpp new file mode 100644 index 00000000000..ebc3ec51811 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.cpp @@ -0,0 +1,148 @@ +#include "server.hpp" + +#include <chrono> +#include <iostream> +#include <thread> + +#include <vsomeip/enumeration_types.hpp> +#include <vsomeip/message.hpp> +#include <vsomeip/payload.hpp> +#include <vsomeip/runtime.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "config.hpp" + +server::server() : applet{"server"}, counter_event_sent{}, counter_method_request{}, counter_method_response{} +{ +} + +void +server::init() { + applet::init(); + + std::weak_ptr<server> its_me + = std::dynamic_pointer_cast<server>(shared_from_this()); + + this->application->register_message_handler( + config::SERVICE_ID, + config::INSTANCE_ID, + config::METHOD_ID, + [its_me](const std::shared_ptr<vsomeip_v3::message>& message){ + auto me = its_me.lock(); + if (me) { + std::shared_ptr runtime = vsomeip_v3::runtime::get(); + std::shared_ptr payload = message->get_payload(); + + switch(message->get_message_type()) + { + case vsomeip_v3::message_type_e::MT_REQUEST: + VSOMEIP_INFO << "GOT REQUEST"; + me->counter_method_request++; + { + std::shared_ptr response = runtime->create_response(message); + response->set_payload(payload); + + me->application->send(response); + me->counter_method_response++; + + me->application->notify( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID, + payload, + true + ); + me->counter_event_sent++; + } + break; + + default: + VSOMEIP_ERROR << "unhandled message type: " + << unsigned(message->get_message_type()); + } + } + } + ); + + this->application->offer_event( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID, + {config::EVENTGROUP_ID}, + vsomeip_v3::event_type_e::ET_FIELD, + {}, + false, + true, + nullptr, + vsomeip_v3::reliability_type_e::RT_UNRELIABLE + ); + + std::thread{ + [its_me]{ + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + + auto me = its_me.lock(); + std::shared_ptr runtime = vsomeip_v3::runtime::get(); + std::shared_ptr payload = runtime->create_payload(); + for(int i = 0; i < 10; i++) + { + int j = i | 0x30; + payload->set_data(reinterpret_cast<vsomeip_v3::byte_t*>(&j), sizeof(j)); + me->application->notify( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID, + payload, + true + ); + me->counter_event_sent++; + + std::this_thread::sleep_for(1s); + } + } + }.detach(); + +} + +server::~server() +{ + this->application->stop_offer_event( + config::SERVICE_ID, + config::INSTANCE_ID, + config::EVENT_ID + ); + + this->application->stop_offer_service( + config::SERVICE_ID, + config::INSTANCE_ID + ); +} + +std::size_t server::get_event_count() noexcept +{ + return this->counter_event_sent; +} + +std::size_t server::get_method_request_count() noexcept +{ + return this->counter_method_request; +} + +std::size_t server::get_method_response_count() noexcept +{ + return this->counter_method_response; +} + +void server::on_state_registered() +{ + this->application->offer_service( + config::SERVICE_ID, + config::INSTANCE_ID + ); +} + +void server::on_state_deregistered() +{ + VSOMEIP_WARNING << "Server is deregistered!!! Probably could not be registered!!!"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.hpp new file mode 100644 index 00000000000..d6da8d7eabf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/server.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <atomic> +#include <cstddef> +#include <memory> + +#include "applet.hpp" + +struct server final : applet +{ + server(); + ~server(); + + void init(); + + std::size_t get_event_count() noexcept; + std::size_t get_method_request_count() noexcept; + std::size_t get_method_response_count() noexcept; + +private: + void on_state_registered() override; + void on_state_deregistered() override; + + std::atomic_size_t counter_event_sent; + std::atomic_size_t counter_method_request; + std::atomic_size_t counter_method_response; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/vsomeip.json b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/vsomeip.json new file mode 100644 index 00000000000..f8ec145ece6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/internal_routing_disabled_acceptance_test/vsomeip.json @@ -0,0 +1,35 @@ +{ + "logging": { + "level": "trace", + "console": "true" + }, + "applications": [ + { + "name": "server", + "id": "0x1001" + }, + { + "name": "client", + "id": "0x1002" + } + ], + "services": [ + { + "service": "0x2222", + "instance": "0x3333", + "unreliable": 12345 + } + ], + "routing": { + "enabled": "false", + "host": "server", + "address": "127.0.0.1", + "port": 1270 + }, + "service-discovery": { + "enable": "true", + "multicast": "224.244.224.244", + "port": 2240, + "protocol": "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/CMakeLists.txt new file mode 100644 index 00000000000..1481260dcb2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/CMakeLists.txt @@ -0,0 +1,183 @@ +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +set (VSOMEIP_NAME vsomeip3) + +# Add the gtest header files to the include files +include_directories( + . + ${gtest_SOURCE_DIR}/include +) + +set(TEST_LINK_LIBRARIES gtest) +if (${CMAKE_SYSTEM_NAME} MATCHES "QNX") + set(TEST_LINK_LIBRARIES ${TEST_LINK_LIBRARIES} socket) +endif() +set(NETWORK_TEST_BIN_DIR ${PROJECT_BINARY_DIR}/test/network_tests) +set(NETWORK_TEST_SRC_DIR ${PROJECT_SOURCE_DIR}/test/network_tests) +set(HOSTNAME "$ENV{HOSTNAME}") + +# Configures the given files into the build folder. +# +# This function looks for files in the `conf` folder with the same name as the +# given files, and ending in `.in`. It will then copy these files into the build +# folder, and replace variables marked with @VARIABLE@ with their actual value. +# +# # Example +# +# set(configuration_files +# my_test_config.json +# my_test_starter.sh +# ) +# configure_files("${configuration_files}") +function(configure_files files) + foreach(item ${files}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/conf/${item}.in + ${CMAKE_CURRENT_BINARY_DIR}/${item} + @ONLY + ) + endforeach() +endfunction() + +# Links the given targets to the default libraries. +# +# These include libraries that are used by nearly every test, such as vsomeip, +# boost, gtest, etc. +# +# # Example +# +# set(executables +# my_test_service +# my_test_client +# ) +# targets_link_default_libraries("${executables}") +function(targets_link_default_libraries targets) + foreach(target ${targets}) + target_link_libraries(${target} + ${VSOMEIP_NAME} + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${TEST_LINK_LIBRARIES} + ${DLT_LIBRARIES} + vsomeip_utilities + ) + endforeach() +endfunction() + +# Adds build dependencies to the given targets. +# +# These ensure that the targets will be built alongside `gtest` and +# `build_network_tests` targets. +# +# # Example +# +# set(executables +# my_test_service +# my_test_client +# ) +# targets_add_default_dependencies("${executables}") +function(targets_add_default_dependencies targets) + foreach(target ${targets}) + add_dependencies(${target} gtest) + add_dependencies(build_network_tests ${target}) + endforeach() +endfunction() + +# Adds a custom command to be called by ctest. +# +# Options include timeouts and environment variables. +# +# Handles the necessary steps to allow calling the test with valgrind, etc. +# +# # Example +# +# add_custom_test( +# NAME my_test_name +# COMMAND ${CMAKE_CURRENT_BINARY_DIR}/my_test_starter.sh ARG1 ARG2... +# TIMEOUT 60 # Optional. Defaults to 120s. +# ENVIRONMENT VSOMEIP_CONFIGURATION=my_test_config.json # Optional. +# ) +function(add_custom_test) + set(options "") + set(oneValueArgs NAME TIMEOUT) + set(multiValueArgs COMMAND ENVIRONMENT) + cmake_parse_arguments(MY_TEST + "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} + ) + + # Replace "test_name" in TEST_ENTRYPOINT with the actual test name. + string(REPLACE + "test_name" "${MY_TEST_NAME}" custom_test_entrypoint "${TEST_ENTRYPOINT}" + ) + + # Add a custom test command. + add_test( + NAME ${MY_TEST_NAME} + COMMAND ${custom_test_entrypoint} ${MY_TEST_COMMAND} + ) + + if(NOT MY_TEST_TIMEOUT) + # Set the default timeout to 120 seconds. + set(MY_TEST_TIMEOUT 120) + endif() + + # Set a timeout for the test. + set_tests_properties(${MY_TEST_NAME} + PROPERTIES TIMEOUT ${MY_TEST_TIMEOUT} + ) + + if(MY_TEST_ENVIRONMENT) + # Set environment variables for the test. + set_property( + TEST ${MY_TEST_NAME} + APPEND PROPERTY ENVIRONMENT + "${MY_TEST_ENVIRONMENT}" + ) + endif() +endfunction() + +### ADD TESTS SUBDIRECTORIES ### +if(NOT ${TESTS_BAT}) + add_subdirectory(client_id_tests) + add_subdirectory(initial_event_tests) + add_subdirectory(subscribe_notify_one_tests) + add_subdirectory(subscribe_notify_tests) + add_subdirectory(restart_routing_tests) + add_subdirectory(configuration_tests) + add_subdirectory(cpu_load_tests) + add_subdirectory(debounce_callback_tests) + add_subdirectory(debounce_filter_tests) + add_subdirectory(debounce_frequency_tests) + add_subdirectory(debounce_tests) + add_subdirectory(e2e_tests) + add_subdirectory(event_tests) + add_subdirectory(lazy_load_tests) + add_subdirectory(magic_cookies_tests) + add_subdirectory(malicious_data_tests) + add_subdirectory(memory_tests) + add_subdirectory(offer_stop_offer_test) + add_subdirectory(offered_services_info_tests) + add_subdirectory(pending_subscription_tests) + add_subdirectory(regression_tests) + add_subdirectory(second_address_tests) + add_subdirectory(security_tests) + add_subdirectory(someip_tp_tests) + add_subdirectory(offer_tests) + add_subdirectory(suspend_resume_tests) +endif() + +add_subdirectory(application_tests) +add_subdirectory(routing_tests) +add_subdirectory(big_payload_tests) +add_subdirectory(header_factory_tests) +add_subdirectory(npdu_tests) +add_subdirectory(payload_tests) +add_subdirectory(cyclic_event_tests) + +# some tests require the routingmanagerd +if (NOT MSVC) +add_dependencies(build_network_tests routingmanagerd) +endif () diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/CMakeLists.txt new file mode 100644 index 00000000000..65dd6eabea3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/CMakeLists.txt @@ -0,0 +1,122 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(application_tests LANGUAGES CXX) + +# Configure necessary files and copy them to the build folder. +set(configuration_files + application_test.json + application_test_daemon.json + application_test_no_dispatch_threads.json + application_test_no_dispatch_threads_daemon.json + application_test_dispatch_threads.json + application_test_starter.sh + application_test_dispatch_threads_starter.sh + application_test_dispatch_threads_executor_starter.sh +) +configure_files("${configuration_files}") + +# Add the test executable. +add_executable(application_test + application_test.cpp +) + +# Add the test executable for application_test_multiple_init +add_executable(application_test_multiple_init + application_test_multiple_init.cpp +) + +# Add the test executable for application_test_dispatch_threads_executor +add_executable(application_test_dispatch_threads_executor + application_test_dispatch_threads_executor.cpp +) + +# Add the test executable for application_test_dispatch_threads +add_executable(application_test_dispatch_threads + application_test_dispatch_threads.cpp +) + +# Add build dependencies and link libraries to executables. +set(executable_targets + application_test + application_test_multiple_init + application_test_dispatch_threads + application_test_dispatch_threads_executor +) +targets_add_default_dependencies("${executable_targets}") +targets_link_default_libraries("${executable_targets}") + +# Add custom test command. +add_custom_test( + NAME application_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/application_test_starter.sh + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME application_test_multiple_init + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/application_test_multiple_init + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME application_test_dispatch_threads_executor + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/application_test_dispatch_threads_executor_starter.sh + TIMEOUT 180 +) + +if (NOT ${TESTS_BAT}) + + # Configure necessary files and copy them to the build folder. + set(configuration_files + application_test_single_process.json + application_test_single_process_starter.sh + application_test_availability_starter.sh + ) + configure_files("${configuration_files}") + + # Add the test executable. + add_executable(application_test_single_process + application_test_single_process.cpp + ) + + if(QNX) + target_compile_definitions(application_test_single_process + PRIVATE _QNX_SOURCE + ) + endif() + + # Add the test executable. + add_executable(application_test_availability + application_test_availability.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executable_targets + application_test_single_process + application_test_availability + ) + targets_add_default_dependencies("${executable_targets}") + targets_link_default_libraries("${executable_targets}") + + # Add custom test command. + add_custom_test( + NAME application_test_single_process + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/application_test_single_process_starter.sh + TIMEOUT 80 + ) + + # Add custom test command. + add_custom_test( + NAME application_test_availability + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/application_test_availability_starter.sh + TIMEOUT 80 + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test.cpp new file mode 100644 index 00000000000..c70b6cd5c71 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test.cpp @@ -0,0 +1,476 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "someip_test_globals.hpp" + +using namespace vsomeip; + +class someip_application_test: public ::testing::Test { +public: + someip_application_test() : + registered_(false) { + + } +protected: + void SetUp() { + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&someip_application_test::on_state, this, + std::placeholders::_1)); + } + + void on_state(vsomeip::state_type_e _state) { + registered_ = (_state == vsomeip::state_type_e::ST_REGISTERED); + } + + bool registered_; + std::shared_ptr<application> app_; +}; + +/** + * @test Start and stop application + */ +TEST_F(someip_application_test, start_stop_application) +{ + std::promise<bool> its_promise; + std::thread t([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); +} + +/** + * @test Start and stop application multiple times + */ +TEST_F(someip_application_test, start_stop_application_multiple) +{ + for (int i = 0; i < 10; ++i) { + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); + } +} + +/** + * @test Start and stop application multiple times and offer a service + */ +TEST_F(someip_application_test, start_stop_application_multiple_offer_service) +{ + for (int i = 0; i < 10; ++i) { + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + app_->stop(); + t.join(); + } +} + +/** + * @test Try to start an already running application again + */ +TEST_F(someip_application_test, restart_without_stopping) +{ + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + VSOMEIP_WARNING << "An error message should appear now"; + // should print error + app_->start(); + app_->stop(); + t.join(); +} + +/** + * @test Try to stop a running application twice + */ +TEST_F(someip_application_test, stop_application_twice) +{ + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->stop(); + t.join(); + app_->stop(); +} + +/** + * @test Checks whether watchdog handler is invoked (regularly) also after restarting. + */ +TEST_F(someip_application_test, watchdog_handler) +{ + std::atomic<int> cb_count(0); + auto wd_handler = [&] () { + ++cb_count; + }; + + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1)); + + std::promise<bool> its_promise; + std::thread t([&]() { + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + + // wait till watchdog handler has been invoked once + while (0 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_EQ(1, cb_count.load()); + + // clear handler (must not be called again) + app_->set_watchdog_handler(nullptr, std::chrono::seconds::zero()); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called again + ASSERT_EQ(1, cb_count.load()); + + // enable handler again + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds(1)); + + // wait till watchdog handler has been invoked again (2nd time) + while (1 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + app_->stop(); + t.join(); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called after stop() + ASSERT_EQ(2, cb_count.load()); + + // restart application (w/ watchdog handler still set) + std::promise<bool> its_promise2; + std::thread t2([&]() { + its_promise2.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise2.get_future().get()); + + // wait till watchdog handler has been invoked again (3rd time) + while (2 == cb_count.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_EQ(3, cb_count.load()); + + // clear handler again (must not be called again), this time via zero interval + app_->set_watchdog_handler(std::cref(wd_handler), std::chrono::seconds::zero()); + + // wait doubled interval (used previously).. + std::this_thread::sleep_for(std::chrono::seconds(2)); + // .. to ensure it was not called again + ASSERT_EQ(3, cb_count.load()); + + app_->stop(); + t2.join(); +} + +class someip_application_shutdown_test: public ::testing::Test { + +protected: + void SetUp() { + is_registered_ = false; + is_available_ = false; + + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&someip_application_shutdown_test::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&someip_application_shutdown_test::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_shutdown_test::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + shutdown_thread_ = std::thread(&someip_application_shutdown_test::send_shutdown_message, this); + + app_->start(); + } + + void TearDown() { + shutdown_thread_.join(); + app_->stop(); + app_.reset(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + (void)_service; + (void)_instance; + if(_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_shutdown(const std::shared_ptr<message>& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + app_->clear_all_handler(); + app_->stop(); + } + + void send_shutdown_message() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_registered_) { + if (std::cv_status::timeout + == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE()<< "Application wasn't registered in time!"; + is_registered_ = true; + } + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while (!is_available_) { + if (std::cv_status::timeout + == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE()<< "Service didn't become available in time!"; + is_available_ = true; + } + } + } + + std::shared_ptr<message> r = runtime::get()->create_request(); + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(r); + } + + bool is_registered_; + bool is_available_; + std::shared_ptr<application> app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread shutdown_thread_; +}; + +class someip_application_exception_test: public ::testing::Test { + +protected: + void SetUp() { + is_registered_ = false; + is_available_ = false; + exception_method_called_ = false; + + app_ = runtime::get()->create_application("application_test"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&someip_application_exception_test::on_message_shutdown, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1, + std::bind(&someip_application_exception_test::on_message_exception, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&someip_application_exception_test::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_exception_test::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + shutdown_thread_ = std::thread(&someip_application_exception_test::send_shutdown_message, this); + + app_->start(); + } + + void TearDown() { + shutdown_thread_.join(); + app_->stop(); + app_.reset(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + (void)_service; + (void)_instance; + if(_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_shutdown(const std::shared_ptr<message>& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + app_->clear_all_handler(); + app_->stop(); + } + + void on_message_exception(const std::shared_ptr<message>& _request) + { + (void)_request; + { + std::lock_guard<std::mutex> its_lock(mutex_); + exception_method_called_ = true; + cv_.notify_one(); + } + throw std::invalid_argument("something went terribly wrong"); + } + + void send_shutdown_message() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while(!is_registered_) { + cv_.wait(its_lock); + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while(!is_available_) { + cv_.wait(its_lock); + } + } + + std::shared_ptr<message> r = runtime::get()->create_request(); + // call method which throws exception + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN+1); + app_->send(r); + + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!exception_method_called_) { + cv_.wait(its_lock); + } + } + + + //shutdown test + r->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + r->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + r->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(r); + } + + bool is_registered_; + bool is_available_; + bool exception_method_called_; + std::shared_ptr<application> app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread shutdown_thread_; +}; + +/** + * @test Stop the application through a method invoked from a dispatcher thread + */ +TEST_F(someip_application_shutdown_test, stop_application_from_dispatcher_thread) { + +} + +/** + * @test Catch unhandled exceptions from invoked handlers + */ +TEST_F(someip_application_exception_test, catch_exception_in_invoked_handler) { + +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_availability.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_availability.cpp new file mode 100644 index 00000000000..9bdf1cdb056 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_availability.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <gtest/gtest.h> + +#include "application_test_client_availability.cpp" +#include "application_test_service.cpp" +#include "application_test_daemon.cpp" + +TEST(someip_application_test_availability, register_availability_handlers) +{ + // start application acting as daemon + application_test_daemon its_daemon; + + // start receiver service + application_test_service its_receiver(application_test::service); + + // start client + application_test_client_availability its_client(application_test::service); + int counter(0); + while (!its_client.all_availability_handlers_called() && counter < 500) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + counter++; + } + + //shutdown + its_receiver.stop(); + its_client.stop(); + its_daemon.stop(); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client.cpp new file mode 100644 index 00000000000..ba05511a46b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client.cpp @@ -0,0 +1,198 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "application_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class application_test_client : public vsomeip_utilities::base_logger { +public: + application_test_client(struct application_test::service_info _service_info) : + vsomeip_utilities::base_logger("APTC", "APPLICATION TEST CLIENT"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("client")), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_for_stop_(true), + received_responses_(0), + sent_requests_(0), + stop_called_(false), + stop_thread_(std::bind(&application_test_client::wait_for_stop, this)), + send_thread_(std::bind(&application_test_client::send, this)) { + if (!app_->init()) { + ADD_FAILURE() << "[Client] Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&application_test_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&application_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(service_info_.service_id, + service_info_.instance_id); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + ~application_test_client() { + send_thread_.join(); + stop_thread_.join(); + application_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "[Client] Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::scoped_lock its_lock {mutex_}; + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available) { + VSOMEIP_INFO << "[Client] Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available" : "not available") << "."; + std::scoped_lock its_lock {mutex_}; + if (_is_available) { + wait_until_service_available_ = false; + condition_.notify_one(); + } else { + wait_until_service_available_ = true; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message>& _message) { + ++received_responses_; + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + VSOMEIP_INFO << "[Client] Received a response with Client/Session [" << std::setfill('0') + << std::hex << std::setw(4) << _message->get_client() << "/" << std::setw(4) + << _message->get_session() << "]"; + } + + void send() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + + while (wait_until_service_available_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + its_lock.unlock(); + its_lock.release(); + + for (;;) { + { + std::scoped_lock its_lock {mutex_}; + if (!wait_until_service_available_ && !stop_called_) { + std::shared_ptr<vsomeip::message> its_req = + vsomeip::runtime::get()->create_request(); + its_req->set_service(service_info_.service_id); + its_req->set_instance(service_info_.instance_id); + its_req->set_method(service_info_.method_id); + app_->send(its_req); + ++sent_requests_; + VSOMEIP_INFO << "[Client] Sent a request to the service!"; + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (stop_called_) { + break; + } + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "[Client] Going down!"; + app_->clear_all_handler(); + app_->stop(); + } + + void stop(bool check) { + stop_called_ = true; + std::scoped_lock its_lock {stop_mutex_}; + wait_for_stop_ = false; + VSOMEIP_INFO << "[Client] Going down. Sent " << sent_requests_ + << " requests and received " << received_responses_ + << " responses. Delta: " << sent_requests_ - received_responses_; + + if (check) { + while (sent_requests_ == 0 || sent_requests_ < received_responses_) { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + // time to be sure the sent message is sent by routing manager + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + EXPECT_GT(sent_requests_, 0u); + EXPECT_GT(received_responses_, 0u); + EXPECT_EQ(sent_requests_, received_responses_); + } + stop_condition_.notify_one(); + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> sent_requests_; + std::atomic<bool> stop_called_; + + std::thread stop_thread_; + std::thread send_thread_; + std::thread application_thread_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client_availability.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client_availability.cpp new file mode 100644 index 00000000000..96aa40521da --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_client_availability.cpp @@ -0,0 +1,207 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> +#include "application_test_globals.hpp" + +class application_test_client_availability : public vsomeip_utilities::base_logger { +public: + application_test_client_availability(struct application_test::service_info _service_info) : + vsomeip_utilities::base_logger("ATCA", "Application Test Client Availability"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("client")), + wait_until_registered_(true), + all_availability_handlers_called_(false), + run_thread_(std::bind(&application_test_client_availability::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_client_availability::on_state, this, + std::placeholders::_1)); + + // register availability handler for every possiblity of + // ANY_SERVICE, ANY_INSTANCE, ANY_MAJOR, ANY_MINOR + for (std::uint32_t i = 0; i < 16; i++) { + vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; + vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; + vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; + vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; + app_->register_availability_handler(its_service, + its_instance, + std::bind(&application_test_client_availability::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, i), + its_major, its_minor); + VSOMEIP_DEBUG << "Registering: " + << std::setfill('0') << std::hex + << std::setw(4) << its_service << "." + << std::setw(4) << its_instance << "." + << std::setw(2) << (std::uint32_t)its_major << "." + << std::setw(4) << its_minor << "." + << i; + + } + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&application_test_client_availability::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, 16), + service_info_.major_version, vsomeip::DEFAULT_MINOR); + VSOMEIP_DEBUG << "Registering: " + << std::setw(4) << std::setfill('0') << std::hex << service_info_.service_id << "." + << std::setw(4) << std::setfill('0') << std::hex << service_info_.instance_id << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)service_info_.service_id << "." + << std::setw(4) << std::setfill('0') << std::hex << vsomeip::DEFAULT_MINOR << "." + << 16; + app_->request_service(service_info_.service_id, + service_info_.instance_id); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + } + + ~application_test_client_availability() { + run_thread_.join(); + application_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available, + std::uint32_t _handler_index) + { + VSOMEIP_DEBUG<< "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << std::setw(4) << std::setfill('0') << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << ". " + << _handler_index; + if(service_info_.service_id == _service + && service_info_.instance_id == _instance) { + std::lock_guard<std::mutex> its_lock(availability_handler_called_mutex_); + availability_handler_called_[_handler_index] = _is_available; + availability_condition_.notify_one(); + } + } + + void run() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + } + while(!app_->is_available(service_info_.service_id, + service_info_.instance_id, service_info_.major_version, + service_info_.minor_version)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + for (std::uint32_t i = 0; i < 16; i++) { + vsomeip::service_t its_service = (i & 0x8) ? service_info_.service_id : vsomeip::ANY_SERVICE; + vsomeip::instance_t its_instance = (i & 0x4) ? service_info_.instance_id : vsomeip::ANY_INSTANCE; + vsomeip::major_version_t its_major = (i & 0x2) ? service_info_.major_version : vsomeip::ANY_MAJOR; + vsomeip::minor_version_t its_minor = (i & 0x1) ? service_info_.minor_version : vsomeip::ANY_MINOR; + + VSOMEIP_DEBUG << "Calling is_available: " + << std::setw(4) << std::setfill('0') << std::hex << its_service << "." + << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." + << std::setw(4) << std::setfill('0') << std::hex << its_minor; + EXPECT_TRUE(app_->is_available(its_service, its_instance, its_major, its_minor)); + + VSOMEIP_DEBUG << "Calling are_available: " + << std::setw(4) << std::setfill('0') << std::hex << its_service << "." + << std::setw(4) << std::setfill('0') << std::hex << its_instance << "." + << std::setw(2) << std::setfill('0') << std::hex << (std::uint32_t)its_major << "." + << std::setw(4) << std::setfill('0') << std::hex << its_minor; + vsomeip::application::available_t are_available; + EXPECT_TRUE(app_->are_available(are_available, its_service, its_instance, its_major, its_minor)); + bool found(false); + auto found_service = are_available.find(service_info_.service_id); + if(found_service != are_available.end()) { + auto found_instance = found_service->second.find(service_info_.instance_id); + if(found_instance != found_service->second.end()) { + auto found_major = found_instance->second.find(service_info_.major_version); + if (found_major != found_instance->second.end()) { + if (found_major->second == service_info_.minor_version) { + found = true; + } + } + } + } + EXPECT_TRUE(found); + + } + { + std::unique_lock<std::mutex> its_lock(availability_handler_called_mutex_); + while(!std::all_of(availability_handler_called_.cbegin(), + availability_handler_called_.cend(), + [&](const availability_handler_called_t::value_type &v) { + return v; + })) { + availability_condition_.wait(its_lock); + } + } + VSOMEIP_INFO << " Everything is available"; + all_availability_handlers_called_ = true; + } + + void stop() { + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + + bool all_availability_handlers_called() const { + return all_availability_handlers_called_; + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + std::mutex availability_handler_called_mutex_; + std::condition_variable availability_condition_; + typedef std::array<bool, 17> availability_handler_called_t; + availability_handler_called_t availability_handler_called_; + + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> all_availability_handlers_called_; + std::thread run_thread_; + std::thread application_thread_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_daemon.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_daemon.cpp new file mode 100644 index 00000000000..d92d020a802 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_daemon.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> +#include <future> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class application_test_daemon : public vsomeip_utilities::base_logger { +public: + application_test_daemon() : + vsomeip_utilities::base_logger("APTD", "APPLICATION TEST DAEMON"), + app_(vsomeip::runtime::get()->create_application("daemon")) { + if (!app_->init()) { + ADD_FAILURE() << "[Daemon] Couldn't initialize application"; + return; + } + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + VSOMEIP_INFO << "[Daemon] Starting"; + } + + ~application_test_daemon() { + application_thread_.join(); + } + + void stop() { + VSOMEIP_INFO << "[Daemon] Stopping"; + app_->stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + std::thread application_thread_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads.cpp new file mode 100644 index 00000000000..33bc35dccd5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads.cpp @@ -0,0 +1,307 @@ +// Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <future> + +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "application_test_globals.hpp" +#include "someip_test_globals.hpp" + +using namespace vsomeip; + +class someip_application_detach_dispatch { + +public: + bool is_registered_; + bool is_available_; + std::atomic_bool is_forcefully_stopped_; + std::atomic_bool is_finished_; + std::shared_ptr<application> app_; + std::condition_variable cv_; + std::mutex mutex_; + std::thread thread_; + + someip_application_detach_dispatch() { } + ~someip_application_detach_dispatch() { } + + void init() { + is_registered_ = false; + is_available_ = false; + + app_ = runtime::get()->create_application("application_test_dispatch_threads"); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID, + std::bind(&someip_application_detach_dispatch::on_message, + this, std::placeholders::_1)); + + app_->register_message_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID_LOOP_SHORT, + std::bind(&someip_application_detach_dispatch::on_message_loop_short, this, + std::placeholders::_1)); + + app_->register_message_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID_LOOP_LONG, + std::bind(&someip_application_detach_dispatch::on_message_loop_long, this, + std::placeholders::_1)); + + app_->register_state_handler(std::bind(&someip_application_detach_dispatch::on_state, this, + std::placeholders::_1)); + app_->register_availability_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&someip_application_detach_dispatch::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + } + + void cleanup() { + app_->stop(); + app_.reset(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + cv_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available) { + (void)_service; + (void)_instance; + if (_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + is_available_ = _is_available; + cv_.notify_one(); + } + } + + void on_message_loop_short(const std::shared_ptr<message>& _request) { + (void)_request; + VSOMEIP_INFO << "Processing something for 5 seconds"; + + pthread_cleanup_push(handler_cbk, nullptr); + + is_finished_ = false; + is_forcefully_stopped_ = false; + + for (int i = 0; i < 6; i++) { + std::unique_lock<std::mutex> its_lock(mutex_); + VSOMEIP_INFO << "Elapsed time: " << i << " seconds"; + + // Call stop after 5 seconds + if (i == 5) { + VSOMEIP_INFO << "Sending stop signal after " << i << " seconds"; + app_->stop(); + } + // using a condition variable instead of sleep_for so that ThreadSanitizer does not + // raise any issues + cv_.wait_for(its_lock, std::chrono::seconds(1)); + pthread_testcancel(); + } + + VSOMEIP_INFO << "Finished processing"; + is_finished_ = true; + pthread_cleanup_pop(0); + } + + void on_message_loop_long(const std::shared_ptr<message>& _request) { + (void)_request; + VSOMEIP_INFO << "Processing something for 50 seconds"; + + pthread_cleanup_push(handler_cbk, this); + + is_finished_ = false; + is_forcefully_stopped_ = false; + + for (int i = 0; i < 50; i++) { + std::unique_lock<std::mutex> its_lock(mutex_); + VSOMEIP_INFO << "Elapsed time: " << i << " seconds"; + + // Call stop after 5 seconds + if (i == 5) { + VSOMEIP_INFO << "Sending stop signal after " << i << " seconds"; + app_->stop(); + } + // using a condition variable instead of sleep_for so that ThreadSanitizer does not + // raise any issues + cv_.wait_for(its_lock, std::chrono::seconds(1)); + pthread_testcancel(); + } + + VSOMEIP_INFO << "Finished processing"; + is_finished_ = true; + pthread_cleanup_pop(0); + } + + void on_message(const std::shared_ptr<message>& _request) { + (void)_request; + VSOMEIP_INFO << "Processing something"; + + std::unique_lock<std::mutex> its_lock(mutex_); + // using a condition variable instead of sleep_for so that ThreadSanitizer does not raise + // any issues + cv_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + + static void handler_cbk(void* arg) { + if (arg != nullptr) { + static_cast<someip_application_detach_dispatch*>(arg)->cleanup_handler(arg); + } + } + + void cleanup_handler(void* arg) { + (void)arg; + VSOMEIP_INFO << "Setting is_forcefully_stopped_ to true"; + is_forcefully_stopped_ = true; + } + + void send_messages(vsomeip_v3::method_t method_id) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_registered_) { + if (std::cv_status::timeout == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE() << "Application wasn't registered in time!"; + is_registered_ = true; + } + } + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); + while (!is_available_) { + if (std::cv_status::timeout == cv_.wait_for(its_lock, std::chrono::seconds(10))) { + ADD_FAILURE() << "Service didn't become available in time!"; + is_available_ = true; + } + } + } + + create_send_request(method_id); + create_send_request(vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID); + } + + void create_send_request(vsomeip_v3::method_t method_id) { + std::shared_ptr<message> t = runtime::get()->create_request(); + t->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + t->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + t->set_method(method_id); + app_->send(t); + } + + void execute(char** argv) { + // Create a shared memory object. + boost::interprocess::shared_memory_object shm( + boost::interprocess::open_only, // only create + "SharedCV", // name + boost::interprocess::read_write // read-write mode + ); + + try { + // Map the whole shared memory in this process + boost::interprocess::mapped_region region( + shm, // What to map + boost::interprocess::read_write // Map it as read-write + ); + + // Get the address of the mapped region + void* addr = region.get_address(); + + // Obtain a pointer to the shared structure + application_test::dispatch_threads_sync* data = + static_cast<application_test::dispatch_threads_sync*>(addr); + + init(); + + std::promise<bool> its_promise; + std::thread t([&]() { app_->start(); }); + + { + boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock( + data->mutex); + + // Set initial value of status_ + data->status_ = application_test::dispatch_threads_sync::TEST_FAILURE; + + // Read to argv[2] timeout and convert to tenths of a second + int timeout = std::stoi(argv[2]) * 10; + + // argv[1] should be the type of test to run + if (strcmp(argv[1], "force_abort") == 0) { + VSOMEIP_INFO << "Testing Force Abort"; + send_messages(vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID_LOOP_LONG); + + for (int i = 0; i < timeout; i++) { + + if (is_forcefully_stopped_ == true && is_finished_ == false) { + VSOMEIP_INFO << "Updating CV"; + data->status_ = + application_test::dispatch_threads_sync::SUCCESS_ABORTING; + data->cv.notify_all(); + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + } else if (strcmp(argv[1], "wait_finish") == 0) { + VSOMEIP_INFO << "Testing Wait Finish"; + send_messages(vsomeip_test::TEST_SERVICE_DETACH_METHOD_ID_LOOP_SHORT); + + for (int i = 0; i < timeout; i++) { + + if (is_forcefully_stopped_ == false && is_finished_ == true) { + VSOMEIP_INFO << "Updating CV"; + data->status_ = + application_test::dispatch_threads_sync::SUCCESS_WAITING; + data->cv.notify_all(); + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + + VSOMEIP_INFO << "Finishing execution"; + + t.join(); + + cleanup(); + + } catch (boost::interprocess::interprocess_exception& ex) { + FAIL() << ex.what(); + } + } +}; + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + (void)argc; + + someip_application_detach_dispatch exec; + exec.execute(argv); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads_executor.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads_executor.cpp new file mode 100644 index 00000000000..e354b15ea38 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_dispatch_threads_executor.cpp @@ -0,0 +1,207 @@ +// Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <future> + +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "application_test_globals.hpp" +#include "someip_test_globals.hpp" + +using namespace vsomeip; + +class someip_application_detach_dispatch_executor : public ::testing::Test { + +protected: + void SetUp() { VSOMEIP_INFO << "Setting up test"; } + + void TearDown() { VSOMEIP_INFO << "Tearing down"; } + + int get_process_pid(std::string process_name) { + std::string file_name = "/tmp/" + process_name + ".pid"; + int pid = -1; + FILE* file = fopen(file_name.c_str(), "r"); + + if (file) { + if (fscanf(file, "%d", &pid) != 1) { // Check that fscanf successfully read one integer + std::cerr << "Failed to read PID from file" << std::endl; + pid = -1; // Indicate failure + } + fclose(file); + } else { + std::cerr << "Failed to open PID file" << std::endl; + } + + return pid; + } + + // Erase previous shared memory and schedule erasure on exit + + boost::interprocess::shared_memory_object shm; + + std::condition_variable cv_; + std::mutex mutex_; +}; + +/** + * @test Force detaching of dispatcher threads with long processing times + */ +TEST_F(someip_application_detach_dispatch_executor, dispatch_thread_detached_forcefully_stopped) { + + struct shm_remove { + shm_remove() { boost::interprocess::shared_memory_object::remove("SharedCV"); } + ~shm_remove() { boost::interprocess::shared_memory_object::remove("SharedCV"); } + } remover; + + // Create a shared memory object. + boost::interprocess::shared_memory_object shm( + boost::interprocess::open_or_create, // only create + "SharedCV", // name + boost::interprocess::read_write // read-write mode + ); + + // Timeout to pass into the test + int seconds_to_timeout = 20; + + // Define how long should the test wait for the condition variable to be set + boost::posix_time::ptime timeout = boost::posix_time::second_clock::local_time() + + boost::posix_time::seconds(seconds_to_timeout); + + try { + // Set size + shm.truncate(sizeof(application_test::dispatch_threads_sync)); + + // Map the whole shared memory in this process + boost::interprocess::mapped_region region( + shm, // What to map + boost::interprocess::read_write // Map it as read-write + ); + + // Get the address of the mapped region + void* addr = region.get_address(); + + // Construct the shared structure in memory + application_test::dispatch_threads_sync* data = + new (addr) application_test::dispatch_threads_sync; + + { + boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock( + data->mutex); + + std::string exec_cmd = "./application_test_dispatch_threads_starter.sh force_abort " + + std::to_string(seconds_to_timeout); + std::cout << std::flush; + + EXPECT_EQ(system(exec_cmd.c_str()), 0); + + EXPECT_EQ(data->cv.timed_wait(lock, timeout, [&] { return data->status_; }), + application_test::dispatch_threads_sync::SUCCESS_ABORTING); + + // Retrieve the PID + int pid = get_process_pid("application_test_dispatch_threads"); + + std::string check_cmd = "kill -0 " + std::to_string(pid); + + if (system(check_cmd.c_str()) + == 0) { // If the process exists, the command will return 0 + std::string kill_cmd = "kill -9 " + std::to_string(pid); + EXPECT_EQ(system(kill_cmd.c_str()), 0); + } + } + } catch (boost::interprocess::interprocess_exception& ex) { + std::cout << ex.what() << std::endl; + } +} + +/** + * @test Force detaching of dispatcher threads with but dispatcher finishes processing + */ +TEST_F(someip_application_detach_dispatch_executor, dispatch_thread_detached_finishes_execution) { + + struct shm_remove { + shm_remove() { boost::interprocess::shared_memory_object::remove("SharedCV"); } + ~shm_remove() { boost::interprocess::shared_memory_object::remove("SharedCV"); } + } remover; + + // Create a shared memory object. + boost::interprocess::shared_memory_object shm( + boost::interprocess::open_or_create, // only create + "SharedCV", // name + boost::interprocess::read_write // read-write mode + ); + + VSOMEIP_INFO << "Starting test"; + + // Timeout to pass into the test + int seconds_to_timeout = 8; + + // Define how long should the test wait for the condition variable to be set + boost::posix_time::ptime timeout = boost::posix_time::second_clock::local_time() + + boost::posix_time::seconds(seconds_to_timeout); + + VSOMEIP_INFO << "Timeout set to " << timeout; + + try { + // Set size + shm.truncate(sizeof(application_test::dispatch_threads_sync)); + + // Map the whole shared memory in this process + boost::interprocess::mapped_region region( + shm, // What to map + boost::interprocess::read_write // Map it as read-write + ); + + // Get the address of the mapped region + void* addr = region.get_address(); + + // Construct the shared structure in memory + application_test::dispatch_threads_sync* data = + new (addr) application_test::dispatch_threads_sync; + + { + boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock( + data->mutex); + + std::string exec_cmd = "./application_test_dispatch_threads_starter.sh wait_finish " + + std::to_string(seconds_to_timeout); + + ASSERT_EQ(system(exec_cmd.c_str()), 0); + + EXPECT_EQ(data->cv.timed_wait(lock, timeout, [&] { return data->status_; }), + application_test::dispatch_threads_sync::SUCCESS_WAITING); + + // Retrieve the PID + int pid = get_process_pid("application_test_dispatch_threads"); + + std::string check_cmd = "kill -0 " + std::to_string(pid); + + if (system(check_cmd.c_str()) + == 0) { // If the process exists, the command will return 0 + std::string kill_cmd = "kill -9 " + std::to_string(pid); + EXPECT_EQ(system(kill_cmd.c_str()), 0); + } + } + } catch (boost::interprocess::interprocess_exception& ex) { + std::cout << ex.what() << std::endl; + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_globals.hpp new file mode 100644 index 00000000000..7843d702573 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_globals.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef APPLICATION_TEST_GLOBALS_HPP_ +#define APPLICATION_TEST_GLOBALS_HPP_ + +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include <boost/interprocess/sync/interprocess_condition.hpp> + +namespace application_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::major_version_t major_version; + vsomeip::minor_version_t minor_version; +}; + +struct service_info service = {0x1111, 0x1, 0x1111, 0x1111, 0x1000, 0x1404, 0x2, 0x4711}; + +struct dispatch_threads_sync { + enum test_status { SUCCESS_ABORTING = 0x00, SUCCESS_WAITING = 0x01, TEST_FAILURE = 0x02 }; + + boost::interprocess::interprocess_mutex mutex; + boost::interprocess::interprocess_condition cv; + + test_status status_; +}; + +static constexpr int number_of_messages_to_send = 150; +} + +#endif /* APPLICATION_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_multiple_init.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_multiple_init.cpp new file mode 100644 index 00000000000..1f462d6c5cc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_multiple_init.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vector> +#include <thread> +#include <mutex> +#include <condition_variable> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +/// @brief This test validates that no data race occurs when calling vsomeip::application_impl::init +/// on multiple applications, within the same process. +TEST(someip_application_init_test, multithread_init) { + constexpr std::uint32_t thread_count = 128; + std::vector<std::thread> vsomeip_applications; + + std::condition_variable start_cv; + std::mutex start_mutex; + std::atomic_bool start = false; + + // Prepare the init threads + for (std::uint32_t t = 0; t < thread_count; ++t) { + vsomeip_applications.emplace_back([&start_cv, &start_mutex, &start, t] { + { + std::unique_lock lk {start_mutex}; + start_cv.wait(lk, [&start] { return start.load(); }); + } + std::stringstream app_name; + app_name << "vsomeip_app_" << t; + auto vsomeip_app = vsomeip::runtime::get()->create_application(app_name.str()); + + EXPECT_TRUE(vsomeip_app->init()); // EXPECT also no crash + }); + } + + // Start the init threads + { + std::scoped_lock lk {start_mutex}; + start = true; + start_cv.notify_all(); + } + + // After test -> join threads + for (auto& t : vsomeip_applications) { + ASSERT_TRUE(t.joinable()); + t.join(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_service.cpp new file mode 100644 index 00000000000..873dc25fdf6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_service.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <future> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "application_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class application_test_service : public vsomeip_utilities::base_logger { +public: + application_test_service(struct application_test::service_info _service_info) : + vsomeip_utilities::base_logger("APTS", "APPLICATION TEST SERVICE"), + service_info_(_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application("service")), + wait_until_registered_(true), + stop_called_(false), + offer_thread_(std::bind(&application_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "[Service] Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&application_test_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&application_test_service::on_request, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&application_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + std::promise<bool> its_promise; + application_thread_ = std::thread([&](){ + its_promise.set_value(true); + app_->start(); + }); + EXPECT_TRUE(its_promise.get_future().get()); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + ~application_test_service() { + offer_thread_.join(); + application_thread_.join(); + } + + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id, + service_info_.major_version, service_info_.minor_version); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "[Service] Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." + : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_INFO << "[Service] Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_session() + << "]"; + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + stop(); + } + + void stop() { + stop_called_ = true; + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id, + service_info_.major_version, service_info_.minor_version); + app_->clear_all_handler(); + app_->stop(); + } + + void run() { + VSOMEIP_DEBUG << "[Service] [" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] is running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_ && !stop_called_) { + condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + + VSOMEIP_DEBUG << "[Service] [" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] is offering"; + offer(); + } + +private: + struct application_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> stop_called_; + std::thread offer_thread_; + std::thread application_thread_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_single_process.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_single_process.cpp new file mode 100644 index 00000000000..4fcf5cfc3c5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/application_test_single_process.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> +#include "application_test_service.cpp" +#include "application_test_client.cpp" +#include "application_test_daemon.cpp" + +TEST(someip_application_test_single_process, notify_increasing_counter) +{ + // start application acting as daemon (rm_stub) + auto its_daemon = std::make_shared<application_test_daemon>(); + + // start receiver service (rm_proxy) + application_test_service its_receiver(application_test::service); + + // stop the daemon (rm_stub goes away) + its_daemon->stop(); + its_daemon.reset(); + // restart client which tries to communicate with service multiple times + // thus it will always be the new routing manager + for (int var = 0; var < 10; ++var) { + // every time the client is restarted it becomes the rm_stub again + application_test_client its_client(application_test::service); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + if(var != 9) { + its_client.stop(false); + } else { + its_client.stop(true); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + its_receiver.on_shutdown_method_called(vsomeip::runtime::get()->create_message()); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test.json.in new file mode 100644 index 00000000000..628283496cd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test.json.in @@ -0,0 +1,38 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788", + "num_dispatchers":"5" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"application_test", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_availability_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_availability_starter.sh.in new file mode 100755 index 00000000000..645e347a0cf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_availability_starter.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_CONFIGURATION=application_test_single_process.json +./application_test_availability + + exit $? \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_daemon.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_daemon.json.in new file mode 100644 index 00000000000..cb3179820ee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_daemon.json.in @@ -0,0 +1,38 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788", + "num_dispatchers":"5" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads.json.in new file mode 100644 index 00000000000..f65e893ae48 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads.json.in @@ -0,0 +1,39 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"application_test_dispatch_threads", + "id":"0x7788", + "num_dispatchers":"5", + "max_detached_thread_wait_time":"5" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"application_test_dispatch_threads", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_executor_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_executor_starter.sh.in new file mode 100755 index 00000000000..b76444c779b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_executor_starter.sh.in @@ -0,0 +1,8 @@ +#!/bin/bash +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_CONFIGURATION=application_test_dispatch_threads.json +./application_test_dispatch_threads_executor diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_starter.sh.in new file mode 100755 index 00000000000..fa294a813b7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_dispatch_threads_starter.sh.in @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_CONFIGURATION=application_test_dispatch_threads.json +./application_test_dispatch_threads "$1" "$2" & +PROCESS_PID=$! +echo $PROCESS_PID > /tmp/application_test_dispatch_threads.pid + +if [ $? -ne 0 ] +then + exit 1 +else + exit 0 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in new file mode 100644 index 00000000000..beb4dc53654 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads.json.in @@ -0,0 +1,37 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"application_test", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in new file mode 100644 index 00000000000..890d14017e0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_no_dispatch_threads_daemon.json.in @@ -0,0 +1,37 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"application_test", + "id":"0x7788" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable":"30503" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process.json.in new file mode 100644 index 00000000000..71c6383ea8f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process.json.in @@ -0,0 +1,14 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/someip.log" + }, + "dlt":"true" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process_starter.sh.in new file mode 100755 index 00000000000..39193581c4a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_single_process_starter.sh.in @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=application_test_single_process.json +./application_test_single_process + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_starter.sh.in new file mode 100755 index 00000000000..00a7d09bc28 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/application_tests/conf/application_test_starter.sh.in @@ -0,0 +1,61 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=application_test_no_dispatch_threads.json +./application_test + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +export VSOMEIP_CONFIGURATION=application_test.json +./application_test + +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Now running same tests with routingmanagerd +******************************************************************************* +******************************************************************************* +End-of-message +export VSOMEIP_CONFIGURATION=application_test_no_dispatch_threads_daemon.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! +./application_test +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +kill $DAEMON_PID +wait $DAEMON_PID + +export VSOMEIP_CONFIGURATION=application_test_daemon.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! +./application_test +if [ $? -ne 0 ] +then + ((FAIL+=1)) +fi + +kill $DAEMON_PID + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/CMakeLists.txt new file mode 100644 index 00000000000..8aa86d73608 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/CMakeLists.txt @@ -0,0 +1,141 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(big_payload_tests LANGUAGES CXX) + +# Configure the necessary files into the build folder. +set(configuration_files + big_payload_test_client_local_start.sh + big_payload_test_external_client_start.sh + big_payload_test_external_service_start.sh + big_payload_test_external_starter.sh + big_payload_test_local.json + big_payload_test_local_limited.json + big_payload_test_local_queue_limited.json + big_payload_test_local_random.json + big_payload_test_local_starter.sh + big_payload_test_local_tcp_client.json + big_payload_test_local_tcp_client_limited.json + big_payload_test_local_tcp_client_queue_limited.json + big_payload_test_local_tcp_client_random.json + big_payload_test_local_tcp_client_start.sh + big_payload_test_local_tcp_service.json + big_payload_test_local_tcp_service_limited.json + big_payload_test_local_tcp_service_queue_limited.json + big_payload_test_local_tcp_service_random.json + big_payload_test_local_tcp_service_start.sh + big_payload_test_local_tcp_starter.sh + big_payload_test_service_local_start.sh + big_payload_test_tcp_client.json + big_payload_test_tcp_client_limited_general.json + big_payload_test_tcp_client_queue_limited_general.json + big_payload_test_tcp_client_queue_limited_specific.json + big_payload_test_tcp_client_random.json + big_payload_test_tcp_service.json + big_payload_test_tcp_service_limited_general.json + big_payload_test_tcp_service_queue_limited_general.json + big_payload_test_tcp_service_queue_limited_specific.json + big_payload_test_tcp_service_random.json + big_payload_test_udp_client.json + big_payload_test_udp_service.json +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(big_payload_test_service + big_payload_test_service.cpp +) + +# Add test executable. +add_executable(big_payload_test_client + big_payload_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(test_executables + big_payload_test_service + big_payload_test_client +) +targets_link_default_libraries("${test_executables}") +targets_add_default_dependencies("${test_executables}") + +# Add custom test commands. + +add_custom_test( + NAME big_payload_test_local + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_starter.sh +) + +add_custom_test( + NAME big_payload_test_local_random + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_starter.sh RANDOM +) + +add_custom_test( + NAME big_payload_test_local_limited + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_starter.sh LIMITED +) + +add_custom_test( + NAME big_payload_test_local_queue_limited + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_starter.sh QUEUELIMITEDGENERAL +) + +add_custom_test( + NAME big_payload_test_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_tcp_starter.sh +) + +add_custom_test( + NAME big_payload_test_local_tcp_random + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_tcp_starter.sh RANDOM +) + +add_custom_test( + NAME big_payload_test_local_tcp_limited + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_tcp_starter.sh LIMITED +) + +add_custom_test( + NAME big_payload_test_local_tcp_queue_limited + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_local_tcp_starter.sh QUEUELIMITEDGENERAL +) + +add_custom_test( + NAME big_payload_test_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh +) + +add_custom_test( + NAME big_payload_test_external_random + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh RANDOM +) + +add_custom_test( + NAME big_payload_test_external_limited + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh LIMITED +) + +add_custom_test( + NAME big_payload_test_external_limited_general + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh LIMITEDGENERAL +) + +add_custom_test( + NAME big_payload_test_external_queue_limited_general + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh QUEUELIMITEDGENERAL +) + +add_custom_test( + NAME big_payload_test_external_queue_limited_specific + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh QUEUELIMITEDSPECIFIC +) + +add_custom_test( + NAME big_payload_test_external_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/big_payload_test_external_starter.sh UDP +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.cpp new file mode 100644 index 00000000000..396dae49fdb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.cpp @@ -0,0 +1,304 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "big_payload_test_client.hpp" +#include "big_payload_test_globals.hpp" +#include <common/utility.hpp> + +big_payload_test_client::big_payload_test_client( + bool _use_tcp, big_payload_test::test_mode _test_mode) : + app_(vsomeip::runtime::get()->create_application("big_payload_test_client")), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + blocked_(false), + is_available_(false), + test_mode_(_test_mode), + number_of_messages_to_send_( + test_mode_ == big_payload_test::test_mode::RANDOM ? + big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES_RANDOM : + big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES), + number_of_sent_messages_(0), + number_of_acknowledged_messages_(0), + sender_(std::bind(&big_payload_test_client::run, this)) { + switch (test_mode_) { + case big_payload_test::test_mode::RANDOM: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_RANDOM; + break; + case big_payload_test::test_mode::LIMITED: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_LIMITED; + break; + case big_payload_test::test_mode::LIMITED_GENERAL: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_LIMITED_GENERAL; + break; + case big_payload_test::test_mode::QUEUE_LIMITED_GENERAL: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_GENERAL; + break; + case big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_SPECIFIC; + break; + case big_payload_test::test_mode::UDP: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_UDP; + break; + default: + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID; + break; + } +} + +bool big_payload_test_client::init() +{ + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&big_payload_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&big_payload_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(service_id_, + big_payload_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&big_payload_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void big_payload_test_client::start() +{ + VSOMEIP_INFO << "Starting Client..."; + app_->start(); +} + +void big_payload_test_client::stop() +{ + VSOMEIP_INFO << "Stopping Client..."; + if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + EXPECT_EQ(number_of_acknowledged_messages_, number_of_messages_to_send_ / 4); + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + EXPECT_EQ(number_of_acknowledged_messages_, number_of_messages_to_send_); + } + app_->clear_all_handler(); + app_->stop(); +} + +void big_payload_test_client::join_sender_thread(){ + sender_.join(); + if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + EXPECT_EQ(number_of_acknowledged_messages_, number_of_messages_to_send_ / 4); + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + EXPECT_EQ(number_of_sent_messages_, number_of_acknowledged_messages_); + } else { + EXPECT_EQ(number_of_sent_messages_, number_of_acknowledged_messages_); + } +} + +void big_payload_test_client::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(service_id_, + big_payload_test::TEST_SERVICE_INSTANCE_ID, false); + } +} + +void big_payload_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) +{ + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(service_id_ == _service + && big_payload_test::TEST_SERVICE_INSTANCE_ID == _instance) + { + if(is_available_ && !_is_available) + { + is_available_ = false; + } + else if(_is_available && !is_available_) + { + is_available_ = true; + send(); + } + } +} + +void big_payload_test_client::on_message(const std::shared_ptr<vsomeip::message>& _response) +{ + VSOMEIP_INFO << "Received a response from Service [" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_session() + << "] size: " << std::dec << _response->get_payload()->get_length(); + static vsomeip::session_t last_session(0); + ASSERT_GT(_response->get_session(), last_session); + last_session = _response->get_session(); + + if(test_mode_ == big_payload_test::test_mode::RANDOM) { + ASSERT_LT(_response->get_payload()->get_length(), big_payload_test::BIG_PAYLOAD_SIZE_RANDOM); + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + EXPECT_EQ(big_payload_test::BIG_PAYLOAD_SIZE_UDP, _response->get_payload()->get_length()); + } else { + ASSERT_EQ(_response->get_payload()->get_length(), big_payload_test::BIG_PAYLOAD_SIZE); + } + + bool check(true); + vsomeip::length_t len = _response->get_payload()->get_length(); + vsomeip::byte_t* datap = _response->get_payload()->get_data(); + for(unsigned int i = 0; i < len; ++i) { + check = check && datap[i] == big_payload_test::DATA_SERVICE_TO_CLIENT; + } + if(!check) { + GTEST_FATAL_FAILURE_("wrong data transmitted"); + } + number_of_acknowledged_messages_++; + if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + if (number_of_acknowledged_messages_ == number_of_messages_to_send_ / 4) { + send(); + } + } else if ( number_of_acknowledged_messages_ == number_of_messages_to_send_) { + send(); + } +} + +void big_payload_test_client::send() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); +} + +void big_payload_test_client::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + { + condition_.wait(its_lock); + } + blocked_ = false; + + request_->set_service(service_id_); + request_->set_instance(big_payload_test::TEST_SERVICE_INSTANCE_ID); + request_->set_method(big_payload_test::TEST_SERVICE_METHOD_ID); + + std::srand(static_cast<unsigned int>(std::time(0))); + + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + std::vector<vsomeip::byte_t> its_payload_data; + + for (unsigned int i = 0; i < number_of_messages_to_send_; i++) + { + if (test_mode_ == big_payload_test::test_mode::RANDOM) { + unsigned int datasize(static_cast<unsigned int>(std::rand()) % big_payload_test::BIG_PAYLOAD_SIZE_RANDOM); + its_payload_data.assign(datasize, big_payload_test::DATA_CLIENT_TO_SERVICE); + } else if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + if (i % 2) { + // try to sent a too big payload for half of the messages + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE + 1, + big_payload_test::DATA_CLIENT_TO_SERVICE); + } else { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE, + big_payload_test::DATA_CLIENT_TO_SERVICE); + } + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE_UDP, + big_payload_test::DATA_CLIENT_TO_SERVICE); + } else { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE, + big_payload_test::DATA_CLIENT_TO_SERVICE); + } + its_payload->set_data(its_payload_data); + request_->set_payload(its_payload); + VSOMEIP_INFO << "Client/Session [" << std::setw(4) << std::setfill('0') << std::hex + << request_->get_client() << "/" << std::setw(4) << std::setfill('0') + << std::hex << request_->get_session() + << "] is going to send a request to Service [" << std::setw(4) + << std::setfill('0') << std::hex << request_->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex << request_->get_instance() + << "] size: " << std::dec << request_->get_payload()->get_length() + << ". Sent Messages: " << number_of_sent_messages_ + 1; + app_->send(request_); + if (test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + number_of_sent_messages_++; + } + while(!blocked_) { + if (std::cv_status::timeout + == condition_.wait_for(its_lock, std::chrono::seconds(120))) { + GTEST_FATAL_FAILURE_("Didn't receive all replies within time"); + } else { + if (test_mode_ == big_payload_test::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + EXPECT_EQ(number_of_messages_to_send_ / 4, + number_of_acknowledged_messages_); + } else { + EXPECT_EQ(number_of_sent_messages_, + number_of_acknowledged_messages_); + } + } + } + stop(); +} + +static big_payload_test::test_mode test_mode(big_payload_test::test_mode::UNKNOWN); + +TEST(someip_big_payload_test, send_ten_messages_to_service) +{ + bool use_tcp = (test_mode != big_payload_test::test_mode::UDP); + big_payload_test_client test_client_(use_tcp, test_mode); + if (test_client_.init()) { + test_client_.start(); + test_client_.join_sender_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc > 1) { + if (std::string("RANDOM") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::RANDOM; + } else if (std::string("LIMITED") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::LIMITED; + } else if (std::string("LIMITEDGENERAL") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::LIMITED_GENERAL; + } else if (std::string("QUEUELIMITEDGENERAL") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::QUEUE_LIMITED_GENERAL; + } else if (std::string("QUEUELIMITEDSPECIFIC") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC; + } else if (std::string("UDP") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::UDP; + } + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.hpp new file mode 100644 index 00000000000..bb81fdcb9e5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_client.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef BIGPAYLOADTESTCLIENT_HPP_ +#define BIGPAYLOADTESTCLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> +#include <atomic> + +#include "big_payload_test_globals.hpp" +#include <vsomeip/internal/logger.hpp> + +class big_payload_test_client +{ +public: + big_payload_test_client(bool _use_tcp, big_payload_test::test_mode _random_mode); + bool init(); + void start(); + void stop(); + void join_sender_thread(); + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + void send(); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool is_available_; + big_payload_test::test_mode test_mode_; + std::uint32_t number_of_messages_to_send_; + std::uint32_t number_of_sent_messages_; + std::atomic<std::uint32_t> number_of_acknowledged_messages_; + std::thread sender_; + vsomeip::service_t service_id_; +}; + +#endif /* BIGPAYLOADTESTCLIENT_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_globals.hpp new file mode 100644 index 00000000000..187ff4a04dc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_globals.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef BIG_PAYLOAD_TEST_GLOBALS_HPP_ +#define BIG_PAYLOAD_TEST_GLOBALS_HPP_ + +#include <cstdint> + +namespace big_payload_test { + constexpr std::uint32_t BIG_PAYLOAD_SIZE = 1024*600; + constexpr std::uint32_t BIG_PAYLOAD_SIZE_UDP = 1024*30; + constexpr std::uint32_t BIG_PAYLOAD_SIZE_RANDOM = 1024*1024*10; + constexpr vsomeip::byte_t DATA_SERVICE_TO_CLIENT = 0xAA; + constexpr vsomeip::byte_t DATA_CLIENT_TO_SERVICE = 0xFF; + + constexpr std::uint32_t BIG_PAYLOAD_TEST_NUMBER_MESSAGES = 10; + constexpr std::uint32_t BIG_PAYLOAD_TEST_NUMBER_MESSAGES_RANDOM = 50; + + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID = 0x1234; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_LIMITED = 0x1235; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_RANDOM = 0x1236; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_LIMITED_GENERAL = 0x1237; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_GENERAL = 0x1238; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_SPECIFIC = 0x1239; + constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID_UDP = 0x1240; + + constexpr vsomeip::service_t TEST_SERVICE_INSTANCE_ID = 0x1; + constexpr vsomeip::method_t TEST_SERVICE_METHOD_ID = 0x8421; + + enum test_mode { + RANDOM, + LIMITED, + LIMITED_GENERAL, + QUEUE_LIMITED_GENERAL, + QUEUE_LIMITED_SPECIFIC, + UDP, + UNKNOWN + }; +} + +#endif /* BIG_PAYLOAD_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.cpp new file mode 100644 index 00000000000..31f1a039124 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.cpp @@ -0,0 +1,277 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "big_payload_test_service.hpp" + +#include "big_payload_test_globals.hpp" + +big_payload_test_service::big_payload_test_service(big_payload_test::test_mode _test_mode) : + app_(vsomeip::runtime::get()->create_application("big_payload_test_service")), + is_registered_(false), + blocked_(false), + test_mode_(_test_mode), + number_of_received_messages_(0), + offer_thread_(std::bind(&big_payload_test_service::run, this)) +{ + switch (test_mode_) { + case big_payload_test::test_mode::RANDOM: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES_RANDOM; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_RANDOM; + break; + case big_payload_test::test_mode::LIMITED: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES / 2; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_LIMITED; + break; + case big_payload_test::test_mode::LIMITED_GENERAL: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES / 2; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_LIMITED_GENERAL; + break; + case big_payload_test::test_mode::QUEUE_LIMITED_GENERAL: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES / 2; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_GENERAL; + break; + case big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES / 2; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_QUEUE_LIMITED_SPECIFIC; + break; + case big_payload_test::test_mode::UDP: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID_UDP; + break; + default: + expected_messages_ = big_payload_test::BIG_PAYLOAD_TEST_NUMBER_MESSAGES; + service_id_ = big_payload_test::TEST_SERVICE_SERVICE_ID; + break; + } +} + +bool big_payload_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + std::srand(static_cast<unsigned int>(std::time(0))); + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip::ANY_SERVICE, + big_payload_test::TEST_SERVICE_INSTANCE_ID, + big_payload_test::TEST_SERVICE_METHOD_ID, + std::bind(&big_payload_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&big_payload_test_service::on_state, this, + std::placeholders::_1)); + return true; +} + +void big_payload_test_service::start() +{ + VSOMEIP_INFO << "Starting Service..."; + app_->start(); +} + +void big_payload_test_service::stop() +{ + VSOMEIP_INFO << "Stopping Service..."; + stop_offer(); + app_->clear_all_handler(); + app_->stop(); +} + +void big_payload_test_service::join_offer_thread() +{ + offer_thread_.join(); +} + +void big_payload_test_service::detach_offer_thread() +{ + offer_thread_.detach(); +} + +void big_payload_test_service::offer() { + app_->offer_service(service_id_, + big_payload_test::TEST_SERVICE_INSTANCE_ID); +} + +void big_payload_test_service::stop_offer() { + app_->stop_offer_service(service_id_, + big_payload_test::TEST_SERVICE_INSTANCE_ID); +} + +void big_payload_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void big_payload_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "] size: " << std::dec + << _request->get_payload()->get_length(); + { + std::lock_guard<std::mutex> its_lock(mutex_); + incoming_requests_.push(_request); + condition_.notify_one(); + } + + +} + +void big_payload_test_service::run() +{ + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) { + condition_.wait(its_lock); + } + + offer(); + + // wait for shutdown + blocked_ = false; + while (!blocked_ || !incoming_requests_.empty()) { + if (incoming_requests_.empty()) { + condition_.wait(its_lock); + } + auto _request = incoming_requests_.front(); + incoming_requests_.pop(); + number_of_received_messages_++; + its_lock.unlock(); + + static vsomeip::session_t last_session(0); + ASSERT_GT(_request->get_session(), last_session); + last_session = _request->get_session(); + if (test_mode_ == big_payload_test::test_mode::RANDOM) { + EXPECT_LT(_request->get_payload()->get_length(), big_payload_test::BIG_PAYLOAD_SIZE_RANDOM); + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + EXPECT_EQ(big_payload_test::BIG_PAYLOAD_SIZE_UDP, _request->get_payload()->get_length()); + } else { + EXPECT_EQ(big_payload_test::BIG_PAYLOAD_SIZE, _request->get_payload()->get_length()); + } + bool check(true); + vsomeip::length_t len = _request->get_payload()->get_length(); + vsomeip::byte_t* datap = _request->get_payload()->get_data(); + for(unsigned int i = 0; i < len; ++i) { + check = check && datap[i] == big_payload_test::DATA_CLIENT_TO_SERVICE; + } + if(!check) { + GTEST_FATAL_FAILURE_("wrong data transmitted"); + } + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get() + ->create_payload(); + std::vector<vsomeip::byte_t> its_payload_data; + if (test_mode_ == big_payload_test::test_mode::RANDOM) { + its_payload_data.assign(static_cast<unsigned int>(std::rand()) % big_payload_test::BIG_PAYLOAD_SIZE_RANDOM, + big_payload_test::DATA_SERVICE_TO_CLIENT); + } else if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC) { + if (number_of_received_messages_ % 2) { + // try to send to big response for half of the received messsages. + // this way the client will only get replies for a fourth of his sent + // requests as he tries to sent to big data for every second request + // as well + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE + 1, + big_payload_test::DATA_SERVICE_TO_CLIENT); + } else { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE, + big_payload_test::DATA_SERVICE_TO_CLIENT); + } + } else if (test_mode_ == big_payload_test::test_mode::UDP) { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE_UDP, + big_payload_test::DATA_SERVICE_TO_CLIENT); + } else { + its_payload_data.assign(big_payload_test::BIG_PAYLOAD_SIZE, + big_payload_test::DATA_SERVICE_TO_CLIENT); + } + + its_payload->set_data(its_payload_data); + its_response->set_payload(its_payload); + + app_->send(its_response); + + if(number_of_received_messages_ == expected_messages_) { + ASSERT_EQ(expected_messages_, number_of_received_messages_); + blocked_ = true; + } + its_lock.lock(); + } + } + std::this_thread::sleep_for(std::chrono::seconds(3)); + if (test_mode_ == big_payload_test::test_mode::LIMITED + || test_mode_ == big_payload_test::test_mode::LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_GENERAL + || test_mode_ == big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC + || test_mode_ == big_payload_test::test_mode::UDP) { + EXPECT_EQ(expected_messages_, number_of_received_messages_); + } + stop(); +} + +static big_payload_test::test_mode test_mode(big_payload_test::test_mode::UNKNOWN); + + +TEST(someip_big_payload_test, receive_ten_messages_and_send_reply) +{ + big_payload_test_service test_service(test_mode); + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } else { + test_service.detach_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc > 1) { + if (std::string("RANDOM") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::RANDOM; + } else if (std::string("LIMITED") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::LIMITED; + } else if (std::string("LIMITEDGENERAL") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::LIMITED_GENERAL; + } else if (std::string("QUEUELIMITEDGENERAL") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::QUEUE_LIMITED_GENERAL; + } else if (std::string("QUEUELIMITEDSPECIFIC") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::QUEUE_LIMITED_SPECIFIC; + } else if (std::string("UDP") == std::string(argv[1])) { + test_mode = big_payload_test::test_mode::UDP; + } + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.hpp new file mode 100644 index 00000000000..44af28a957d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/big_payload_test_service.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef BIGPAYLOADTESTSERVICE_HPP_ +#define BIGPAYLOADTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> +#include <queue> + +#include "big_payload_test_globals.hpp" +#include <vsomeip/internal/logger.hpp> + + +class big_payload_test_service +{ +public: + big_payload_test_service(big_payload_test::test_mode _test_mode); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void detach_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + big_payload_test::test_mode test_mode_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; + std::uint32_t expected_messages_; + vsomeip::service_t service_id_; + std::queue<std::shared_ptr<vsomeip::message>> incoming_requests_; +}; + +#endif /* BIGPAYLOADTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_client_local_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_client_local_start.sh.in new file mode 100755 index 00000000000..adbf9f43ff8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_client_local_start.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Start the client +export VSOMEIP_APPLICATION_NAME=big_payload_test_client +export VSOMEIP_CONFIGURATION=big_payload_test_local.json +./big_payload_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_client_start.sh.in new file mode 100755 index 00000000000..5258ce839b9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_client_start.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Start the client +export VSOMEIP_APPLICATION_NAME=big_payload_test_client +export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client.json +./big_payload_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_service_start.sh.in new file mode 100755 index 00000000000..ac8dd60880d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_service_start.sh.in @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if [[ $# -gt 0 && $1 != "RANDOM" && $1 != "LIMITED" && $1 != "LIMITEDGENERAL" && $1 != "QUEUELIMITEDGENERAL" && $1 != "QUEUELIMITEDSPECIFIC" && $1 != "UDP" ]] +then + echo "The only allowed parameter to this script is RANDOM, LIMITED, LIMITEDGENERAL, QUEUELIMITEDGENERAL, QUEUELIMITEDSPECIFIC or UDP" + echo "Like $0 RANDOM" + exit 1 +fi + +# Start the service +if [[ $# -gt 0 && $1 == "RANDOM" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_service_random.json +elif [[ $# -gt 0 && $1 == "LIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_service_limited_general.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_service_queue_limited_general.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDSPECIFIC" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_service_queue_limited_specific.json +elif [[ $# -gt 0 && $1 == "UDP" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_udp_service.json +else + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_service.json +fi +./big_payload_test_service $1 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_starter.sh.in new file mode 100755 index 00000000000..f385a223b00 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_external_starter.sh.in @@ -0,0 +1,77 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit successfully. + +if [[ $# -gt 0 && $1 != "RANDOM" && $1 != "LIMITED" && $1 != "LIMITEDGENERAL" && $1 != "QUEUELIMITEDGENERAL" && $1 != "QUEUELIMITEDSPECIFIC" && $1 != "UDP" ]] +then + echo "The only allowed parameter to this script is RANDOM or LIMITED, LIMITEDGENERAL, QUEUELIMITEDGENERAL, QUEUELIMITEDSPECIFIC or UDP" + echo "Like $0 RANDOM" + exit 1 +fi + +FAIL=0 + +# Start the client +if [[ $# -gt 0 && $1 == "RANDOM" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client_random.json +elif [[ $# -gt 0 && $1 == "LIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client_limited_general.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client_queue_limited_general.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDSPECIFIC" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client_queue_limited_specific.json +elif [[ $# -gt 0 && $1 == "UDP" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_udp_client.json +else + export VSOMEIP_CONFIGURATION=big_payload_test_tcp_client.json +fi +./big_payload_test_client $1 & +BIG_PAYLOAD_TEST_PID=$! + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting big payload test on slave LXC" + if [[ $# -gt 0 ]]; then + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/big_payload_tests; ./big_payload_test_external_service_start.sh $1\"" & + else + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP 'bash -ci "set -m; cd \$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/big_payload_tests; ./big_payload_test_external_service_start.sh"' & + fi +elif [ ! -z "$USE_DOCKER" ]; then + if [[ $# -gt 0 ]]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./big_payload_test_external_service_start.sh $1" & + else + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./big_payload_test_external_service_start.sh" & + fi +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** big_payload_test_external_service_start.sh $1 +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** big_payload_test_tcp_service.json and +** big_payload_test_tcp_client.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if client and server both exited successfully +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local.json.in new file mode 100644 index 00000000000..d8f8b7ad890 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local.json.in @@ -0,0 +1,55 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "payload-sizes": + [ + { + "unicast":"127.0.0.1", + "ports": + [ + { + "port":"30509", + "max-payload-size":"614400" + } + ] + } + ], + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_limited.json.in new file mode 100644 index 00000000000..d497aa41af6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_limited.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"error", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "max-payload-size-local" : "614400", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_queue_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_queue_limited.json.in new file mode 100644 index 00000000000..0ae8c13c4d1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_queue_limited.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "endpoint-queue-limit-local" : "614431", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_random.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_random.json.in new file mode 100644 index 00000000000..0a01ca10362 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_random.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "buffer-shrink-threshold" : "2", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_starter.sh.in new file mode 100755 index 00000000000..747cd2e49cc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_starter.sh.in @@ -0,0 +1,48 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit successfully. + +if [ $# -gt 0 ] && [ "$1" != "RANDOM" ] && [ "$1" != "LIMITED" ] && [ "$1" != "QUEUELIMITEDGENERAL" ]; +then + echo "The only allowed parameter to this script is "RANDOM","LIMITED" or "QUEUELIMITEDGENERAL"." + echo "Like $0 RANDOM" + exit 1 +fi + + +FAIL=0 + +# Start the service +if [ $# -gt 0 ] && [ "$1" = "RANDOM" ]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_random.json +elif [ $# -gt 0 ] && [ $1 = "LIMITED" ]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_limited.json +elif [ $# -gt 0 ] && [ $1 = "QUEUELIMITEDGENERAL" ]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_queue_limited.json +else + export VSOMEIP_CONFIGURATION=big_payload_test_local.json +fi +./big_payload_test_service $1 & +sleep 1 + +# Start the client +if ! ./big_payload_test_client $1 +then + FAIL=$((FAIL+1)) +fi + +# Wait until service is finished +# Fail gets incremented if service exit +# with a non-zero exit code +wait $! || FAIL=$((FAIL+1)) + +# Check if client and server both exited sucessfully +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client.json.in new file mode 100644 index 00000000000..6821e5a5580 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client.json.in @@ -0,0 +1,63 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"error", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "payload-sizes": + [ + { + "unicast":"127.0.0.1", + "ports": + [ + { + "port":"30509", + "max-payload-size":"614400" + } + ] + } + ], + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_limited.json.in new file mode 100644 index 00000000000..cd8dd746f51 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_limited.json.in @@ -0,0 +1,51 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "max-payload-size-local" : "614400", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_queue_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_queue_limited.json.in new file mode 100644 index 00000000000..c5f4910f540 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_queue_limited.json.in @@ -0,0 +1,51 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "endpoint-queue-limit-local" : "614431", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_random.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_random.json.in new file mode 100644 index 00000000000..b0f028898b8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_random.json.in @@ -0,0 +1,51 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "buffer-shrink-threshold" : "2", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_start.sh.in new file mode 100755 index 00000000000..bc7fc972c97 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_client_start.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Start the client +export VSOMEIP_APPLICATION_NAME=big_payload_test_client +export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_client.json +./big_payload_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service.json.in new file mode 100644 index 00000000000..296c910342d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service.json.in @@ -0,0 +1,67 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "payload-sizes": + [ + { + "unicast":"127.0.0.1", + "ports": + [ + { + "port":"30509", + "max-payload-size":"614400" + } + ] + } + ], + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + }, + "guests" : + { + "unicast" : "@TEST_IP_SLAVE@" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_limited.json.in new file mode 100644 index 00000000000..042e26a82b6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_limited.json.in @@ -0,0 +1,55 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "max-payload-size-local" : "614400", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + }, + "guests" : + { + "unicast" : "@TEST_IP_SLAVE@" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_queue_limited.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_queue_limited.json.in new file mode 100644 index 00000000000..402f416d9b1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_queue_limited.json.in @@ -0,0 +1,55 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "endpoint-queue-limit-local" : "614431", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + }, + "guests" : + { + "unicast" : "@TEST_IP_SLAVE@" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_random.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_random.json.in new file mode 100644 index 00000000000..203e6426ea1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_random.json.in @@ -0,0 +1,55 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + }, + { + "name":"big_payload_test_client", + "id":"0x1344", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678" + } + ], + "buffer-shrink-threshold" : "2", + "routing": + { + "host" : + { + "name" : "big_payload_test_client", + "unicast" : "@TEST_IP_MASTER@", + "port" : "31490" + }, + "guests" : + { + "unicast" : "@TEST_IP_SLAVE@" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_start.sh.in new file mode 100755 index 00000000000..5bc73fc7e5c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_service_start.sh.in @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if [[ $# -gt 0 && $1 != "RANDOM" && $1 != "LIMITED" && $1 != "QUEUELIMITEDGENERAL" ]] +then + echo "The only allowed parameter to this script is RANDOM, LIMITED or QUEUELIMITEDGENERAL" + echo "Like $0 RANDOM" + exit 1 +fi + +# Start the service +if [[ $# -gt 0 && $1 == "RANDOM" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_service_random.json +elif [[ $# -gt 0 && $1 == "LIMITED" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_service_limited.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_service_queue_limited.json +else + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_service.json +fi +./big_payload_test_service $1 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_starter.sh.in new file mode 100755 index 00000000000..6cd4e57ceb9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_local_tcp_starter.sh.in @@ -0,0 +1,74 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit successfully. + +if [[ $# -gt 0 && $1 != "RANDOM" && $1 != "LIMITED" && $1 != "QUEUELIMITEDGENERAL" ]] +then + echo "The only allowed parameter to this script is RANDOM or LIMITED or QUEUELIMITEDGENERAL." + echo "Like $0 RANDOM" + exit 1 +fi + + +FAIL=0 + +# Start the service +if [[ $# -gt 0 && $1 == "RANDOM" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_client_random.json +elif [[ $# -gt 0 && $1 == "LIMITED" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_client_limited.json +elif [[ $# -gt 0 && $1 == "QUEUELIMITEDGENERAL" ]]; then + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_client_queue_limited.json +else + export VSOMEIP_CONFIGURATION=big_payload_test_local_tcp_client.json +fi +./big_payload_test_client $1 & +BIG_PAYLOAD_TEST_PID=$! + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting big payload test on slave LXC" + if [[ $# -gt 0 ]]; then + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/big_payload_tests; ./big_payload_test_local_tcp_service_start.sh $1\"" & + else + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP 'bash -ci "set -m; cd \$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/big_payload_tests; ./big_payload_test_local_tcp_service_start.sh"' & + fi +elif [ ! -z "$USE_DOCKER" ]; then + if [[ $# -gt 0 ]]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./big_payload_test_local_tcp_service_start.sh $1" & + else + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./big_payload_test_local_tcp_service_start.sh" & + fi +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** big_payload_test_local_tcp_service_start.sh $1 +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** big_payload_test_local_tcp_service.json and +** big_payload_test_local_tcp_client.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if client and server both exited successfully +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_service_local_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_service_local_start.sh.in new file mode 100755 index 00000000000..299af829908 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_service_local_start.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Start the service +export VSOMEIP_APPLICATION_NAME=big_payload_test_service +export VSOMEIP_CONFIGURATION=big_payload_test_local.json +./big_payload_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client.json.in new file mode 100644 index 00000000000..0f23a10b6dc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343" + } + ], + "payload-sizes": + [ + { + "unicast":"@TEST_IP_SLAVE@", + "ports": + [ + { + "port":"30509", + "max-payload-size":"614400" + } + ] + } + ], + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_limited_general.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_limited_general.json.in new file mode 100644 index 00000000000..f28efc8340f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_limited_general.json.in @@ -0,0 +1,31 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343" + } + ], + "max-payload-size-reliable":"614400", + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_general.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_general.json.in new file mode 100644 index 00000000000..a193ab81513 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_general.json.in @@ -0,0 +1,31 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343" + } + ], + "endpoint-queue-limit-external" : "614416", + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_specific.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_specific.json.in new file mode 100644 index 00000000000..79f3486b702 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_queue_limited_specific.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343" + } + ], + "endpoint-queue-limits" : + [ + { + "unicast":"@TEST_IP_SLAVE@", + "ports": + [ + { + "port":"30509", + "queue-size-limit":"614416" + } + ] + } + ], + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_random.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_random.json.in new file mode 100644 index 00000000000..85cf3936652 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_client_random.json.in @@ -0,0 +1,32 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343", + "max_dispatch_time" : "5000" + } + ], + "buffer-shrink-threshold" : "2", + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service.json.in new file mode 100644 index 00000000000..4313543369e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1235", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1236", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1237", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + } + ], + "payload-sizes": + [ + { + "unicast":"@TEST_IP_SLAVE@", + "ports": + [ + { + "port":"30509", + "max-payload-size":"614400" + } + ] + } + ], + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_limited_general.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_limited_general.json.in new file mode 100644 index 00000000000..0e960eb9f76 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_limited_general.json.in @@ -0,0 +1,69 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1235", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1236", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1237", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + } + ], + "max-payload-size-reliable":"614400", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_general.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_general.json.in new file mode 100644 index 00000000000..861a7b23ff6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_general.json.in @@ -0,0 +1,87 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1235", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1236", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1237", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1238", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1239", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + } + ], + "endpoint-queue-limit-external" : "614416", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_specific.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_specific.json.in new file mode 100644 index 00000000000..5f0547d91dc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_queue_limited_specific.json.in @@ -0,0 +1,99 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1235", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1236", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1237", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1238", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1239", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + } + ], + "endpoint-queue-limits" : + [ + { + "unicast":"@TEST_IP_SLAVE@", + "ports": + [ + { + "port":"30509", + "queue-size-limit":"614416" + } + ] + } + ], + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_random.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_random.json.in new file mode 100644 index 00000000000..2302e103dec --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_tcp_service_random.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatch_time" : "5000" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1235", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1236", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1237", + "instance":"0x01", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"false" + } + } + ], + "buffer-shrink-threshold" : "2", + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_client.json.in new file mode 100644 index 00000000000..d28e5952ae7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_client.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_client", + "id":"0x1343", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1240", + "instance":"0x01", + "unreliable": "30509", + "someip-tp" : { + "client-to-service" : [ "0x8421" ] + } + } + ], + "max-payload-size-reliable":"614400", + "routing":"big_payload_test_client", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_service.json.in new file mode 100644 index 00000000000..e87ca07778c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/big_payload_tests/conf/big_payload_test_udp_service.json.in @@ -0,0 +1,41 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"big_payload_test_service", + "id":"0x1277", + "max_dispatchers" : "0" + } + ], + "services": + [ + { + "service":"0x1240", + "instance":"0x01", + "unreliable": "30509", + "someip-tp" : { + "service-to-client" : [ "0x8421" ] + } + } + ], + "routing":"big_payload_test_service", + "service-discovery": + { + "enable":"true", + "multicast":"224.244.224.245", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/CMakeLists.txt new file mode 100644 index 00000000000..9e5ff137505 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/CMakeLists.txt @@ -0,0 +1,101 @@ +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(client_id_tests LANGUAGES CXX) + +# Configure the necessary files into the build folder. +set(configuration_files + client_id_test_diff_client_ids_diff_ports_master.json + client_id_test_diff_client_ids_diff_ports_slave.json + client_id_test_diff_client_ids_partial_same_ports_master.json + client_id_test_diff_client_ids_partial_same_ports_slave.json + client_id_test_diff_client_ids_same_ports_master.json + client_id_test_diff_client_ids_same_ports_slave.json + client_id_test_master_starter.sh + client_id_test_same_client_ids_diff_ports_master.json + client_id_test_same_client_ids_diff_ports_slave.json + client_id_test_same_client_ids_same_ports_master.json + client_id_test_same_client_ids_same_ports_slave.json + client_id_test_slave_starter.sh + client_id_test_utility.json + client_id_test_utility_discontinuous_masked_511.json + client_id_test_utility_masked_127.json + client_id_test_utility_masked_511.json + client_id_test_utility_masked_4095.json +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(client_id_test_service + client_id_test_service.cpp +) + +# Add test executable. +add_executable(client_id_test_utility + client_id_test_utility.cpp +) + +# Link vsomeip configuration libraries. +target_link_libraries(client_id_test_utility + ${VSOMEIP_NAME}-cfg +) + +# Add build dependencies and link libraries to executables. +set(test_executables + client_id_test_service + client_id_test_utility +) +targets_link_default_libraries("${test_executables}") +targets_add_default_dependencies("${test_executables}") + +# Add custom test commands. + +add_custom_test( + NAME client_id_test_diff_client_ids_diff_ports + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_master_starter.sh client_id_test_diff_client_ids_diff_ports_master.json +) + +add_custom_test( + NAME client_id_test_diff_client_ids_same_ports + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_master_starter.sh client_id_test_diff_client_ids_same_ports_master.json +) + +add_custom_test( + NAME client_id_test_diff_client_ids_partial_same_ports + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_master_starter.sh client_id_test_diff_client_ids_partial_same_ports_master.json +) + +add_custom_test( + NAME client_id_test_utility + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility + ENVIRONMENT "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility.json" +) + +add_custom_test( + NAME client_id_test_utility_masked_511 + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility + ENVIRONMENT "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility_masked_511.json" +) + +add_custom_test( + NAME client_id_test_utility_masked_4095 + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility + ENVIRONMENT "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility_masked_4095.json" + TIMEOUT 600 +) + +add_custom_test( + NAME client_id_test_utility_masked_127 + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility + ENVIRONMENT "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility_masked_127.json" +) + +add_custom_test( + NAME client_id_test_utility_discontinuous_masked_511 + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility + ENVIRONMENT "VSOMEIP_CONFIGURATION=${CMAKE_CURRENT_BINARY_DIR}/client_id_test_utility_discontinuous_masked_511.json" +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_globals.hpp new file mode 100644 index 00000000000..e4b2cb81d69 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_globals.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef CLIENT_ID_TEST_CLIENT_ID_TEST_GLOBALS_HPP_ +#define CLIENT_ID_TEST_CLIENT_ID_TEST_GLOBALS_HPP_ + +namespace client_id_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::client_t offering_client; +}; + +static constexpr std::array<service_info, 7> service_infos = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1000, 0x1, 0x1111, 0x1111 }, + { 0x2000, 0x1, 0x2222, 0x2222}, + { 0x3000, 0x1, 0x3333, 0x3333}, + // node 2 + { 0x4000, 0x1, 0x4444, 0x4444 }, + { 0x5000, 0x1, 0x5555, 0x5555 }, + { 0x6000, 0x1, 0x6666, 0x6666 } +}}; + +static constexpr int messages_to_send = 10; +} + +#endif /* CLIENT_ID_TEST_CLIENT_ID_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_service.cpp new file mode 100644 index 00000000000..4eeb344e732 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_service.cpp @@ -0,0 +1,295 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "client_id_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + + +class client_id_test_service : public vsomeip_utilities::base_logger { +public: + client_id_test_service(struct client_id_test::service_info _service_info) : + vsomeip_utilities::base_logger("CITS", "CLIENT ID TEST SERVICE"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application()), + blocked_(false), + offer_thread_(std::bind(&client_id_test_service::run, this)), + stopped_(false), + stop_thread_(std::bind(&client_id_test_service::wait_for_stop, this)) { + if (!app_->init()) { + offer_thread_.detach(); + stop_thread_.detach(); + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&client_id_test_service::on_state, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&client_id_test_service::on_request, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip::ANY_SERVICE, + service_info_.instance_id, vsomeip::ANY_METHOD, + std::bind(&client_id_test_service::on_response, this, + std::placeholders::_1)); + + for(const auto& i : client_id_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + app_->request_service(i.service_id, i.instance_id); + app_->register_availability_handler(i.service_id, i.instance_id, + std::bind(&client_id_test_service::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false; + other_services_received_response_[std::make_pair(i.service_id, i.method_id)] = 0; + other_services_received_request_[i.offering_client] = 0; + } + + app_->start(); + } + + ~client_id_test_service() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + } + + void stop_offer() { + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + VSOMEIP_INFO + << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available."); + + auto its_service = other_services_available_.find(std::make_pair(_service, _instance)); + if(its_service != other_services_available_.end()) { + its_service->second = true; + } + + if(std::all_of(other_services_available_.cbegin(), + other_services_available_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::instance_t>, bool>::value_type& v) { + return v.second;})) { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + } + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) { + VSOMEIP_DEBUG + << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "]"; + std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get() + ->create_response(_message); + app_->send(its_response); + + other_services_received_request_[_message->get_client()]++; + if(all_responses_and_requests_received()) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + stopped_ = true; + stop_condition_.notify_one(); + } + } + } + + void on_response(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + VSOMEIP_DEBUG + << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] Received a response with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "]"; + other_services_received_response_[std::make_pair(_message->get_service(), + _message->get_method())]++; + + if(all_responses_and_requests_received()) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + stopped_ = true; + stop_condition_.notify_one(); + } + } + } + + bool all_responses_and_requests_received() { + const bool responses = std::all_of( + other_services_received_response_.cbegin(), + other_services_received_response_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::method_t>, std::uint32_t>::value_type& v) + { return v.second == client_id_test::messages_to_send;}); + const bool requests = std::all_of( + other_services_received_request_.cbegin(), + other_services_received_request_.cend(), + [](const std::map<vsomeip::client_t, std::uint32_t>::value_type& v) + { return v.second == client_id_test::messages_to_send;}); + return (responses && requests); + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) { + condition_.wait(its_lock); + } + blocked_ = false; + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + + while (!blocked_) { + condition_.wait(its_lock); + } + blocked_ = false; + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Sending"; + // send a message to all other services + for (int var = 0; var < client_id_test::messages_to_send; ++var) { + for(const client_id_test::service_info& i: client_id_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + std::shared_ptr<vsomeip::message> msg = vsomeip::runtime::get()->create_request(); + msg->set_service(i.service_id); + msg->set_instance(i.instance_id); + msg->set_method(i.method_id); + app_->send(msg); + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') + << std::hex << service_info_.service_id + << "] Sending a request to Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << i.service_id << "/" << std::setw(4) << std::setfill('0') + << std::hex << i.instance_id << "]"; + } + } + + while (!blocked_) { + condition_.wait(its_lock); + } + blocked_ = false; + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (!stopped_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] Received responses and requests from all other services, going down"; + + // let offer thread exit + { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + + std::this_thread::sleep_for(std::chrono::seconds(3)); + app_->clear_all_handler(); + app_->stop(); + } + +private: + client_id_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_response_; + std::map<vsomeip::client_t, std::uint32_t> other_services_received_request_; + + bool blocked_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + + bool stopped_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; +}; + +static int service_number; + +TEST(someip_client_id_test, send_ten_messages_to_service) +{ + client_id_test_service its_sample( + client_id_test::service_infos[static_cast<size_t>(service_number)]); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl; + std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl; + return 1; + } + service_number = std::stoi(std::string(argv[1]), nullptr); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_utility.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_utility.cpp new file mode 100644 index 00000000000..324d47c2eef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/client_id_test_utility.cpp @@ -0,0 +1,611 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <thread> +#include <future> +#include <cstring> + +#include <vsomeip/vsomeip.hpp> +#include "../../implementation/utility/include/utility.hpp" +#include "../../implementation/configuration/include/configuration.hpp" +#include "../../implementation/configuration/include/configuration_plugin.hpp" +#include "../../implementation/plugin/include/plugin_manager_impl.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +using namespace vsomeip; + +static const std::string APPLICATION_NAME_ROUTING_MANAGER = "routingmanagerd"; + +static const std::string APPLICATION_NAME_NOT_PREDEFINED = "test-application-name"; + +vsomeip::client_t CLIENT_ID_ROUTING_MANAGER = 0xFFFF; + +static const std::string APPLICATION_IN_NAME = "client_id_test_utility_service_in"; +static vsomeip::client_t APPLICATION_IN_CLIENT_ID = 0xFFFF; + +static const std::string APPLICATION_IN_NAME_TWO = "client_id_test_utility_service_in_two"; +static vsomeip::client_t APPLICATION_IN_CLIENT_ID_TWO = 0xFFFF; + +static const std::string APPLICATION_OUT_LOW_NAME = "client_id_test_utility_service_out_low"; +static const vsomeip::client_t APPLICATION_OUT_LOW_CLIENT_ID = 0x5911; + +static const std::string APPLICATION_OUT_HIGH_NAME = "client_id_test_utility_service_out_high"; +static const vsomeip::client_t APPLICATION_OUT_HIGH_CLIENT_ID = 0x7411; + +class client_id_utility_test: public ::testing::Test { +public: + client_id_utility_test() : + client_id_routing_manager_(0x0), + diagnosis_(0x0), + diagnosis_mask_(0xFF00), + client_id_base_(0x0) { + + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_config_plugin = std::dynamic_pointer_cast<vsomeip::configuration_plugin>(its_plugin); + if (its_config_plugin) { + configuration_ = its_config_plugin->get_configuration(APPLICATION_NAME_ROUTING_MANAGER, ""); + } + } + } +protected: + virtual void SetUp() { + ASSERT_TRUE(static_cast<bool>(configuration_)); + configuration_->load(APPLICATION_NAME_ROUTING_MANAGER); + diagnosis_mask_ = configuration_->get_diagnosis_mask(); + diagnosis_ = configuration_->get_diagnosis_address(); + + // calculate all client IDs based on mask + client_id_base_ = static_cast<client_t>(diagnosis_ << 8); + CLIENT_ID_ROUTING_MANAGER = + static_cast<client_t>((configuration_->get_diagnosis_address() + << 8) & configuration_->get_diagnosis_mask()); + APPLICATION_IN_CLIENT_ID = static_cast<client_t>(client_id_base_ | 0x11); + APPLICATION_IN_CLIENT_ID_TWO = static_cast<client_t>(client_id_base_ | 0x12); + + app_ = vsomeip::runtime::get()->create_application(APPLICATION_NAME_ROUTING_MANAGER); + EXPECT_TRUE(app_->init()); + EXPECT_EQ(CLIENT_ID_ROUTING_MANAGER, app_->get_client()); + + rm_impl_thread_ = std::thread([&](){ + app_->start(); + }); + // ensure clean preconditions + utility::reset_client_ids(configuration_->get_network()); + + // required as there are two static versions of the utility class in this + // test, one in the test itself and one in libvsomeip... + client_id_routing_manager_ = utility::request_client_id( + configuration_, APPLICATION_NAME_ROUTING_MANAGER, static_cast<client_t>( + (configuration_->get_diagnosis_address() << 8) + & configuration_->get_diagnosis_mask())); + EXPECT_EQ(CLIENT_ID_ROUTING_MANAGER, client_id_routing_manager_); + } + + virtual void TearDown() { + app_->stop(); + if (rm_impl_thread_.joinable()) { + rm_impl_thread_.join(); + } + app_.reset(); + utility::release_client_id(configuration_->get_network(), client_id_routing_manager_); + } + +protected: + std::shared_ptr<configuration> configuration_; + vsomeip::client_t client_id_routing_manager_; + std::uint16_t diagnosis_; + std::uint16_t diagnosis_mask_; + client_t client_id_base_; + std::shared_ptr<vsomeip::application> app_; + std::thread rm_impl_thread_; +}; + +class app_wrapper : public vsomeip_utilities::base_logger { +public: + app_wrapper(const std::string& _name) : + vsomeip_utilities::base_logger("APPW", "APP WRAPPER"), + app_(vsomeip::runtime::get()->create_application(_name)), + client_(VSOMEIP_CLIENT_UNSET) { + EXPECT_TRUE(app_->init()); + app_->register_state_handler( + std::bind(&app_wrapper::on_state, this, std::placeholders::_1)); + app_thread_ = std::thread([&](){ app_->start(); }); + } + + ~app_wrapper() { + app_->stop(); + if (app_thread_.joinable()) { + app_thread_.join(); + } + app_.reset(); + } + + void on_state(const vsomeip::state_type_e& _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + client_ = app_->get_client(); + registered_.set_value(); + } + }; + + client_t get_client() { + if (std::future_status::timeout + == registered_.get_future().wait_for( + std::chrono::seconds(11))) { + ADD_FAILURE()<< __LINE__ << " application wasn't registered within time"; + } + return client_; + } + + std::shared_ptr<vsomeip::application> get_app() { + return app_; + } + +private: + std::shared_ptr<vsomeip::application> app_; + std::promise<void> registered_; + std::thread app_thread_; + std::atomic<vsomeip::client_t> client_; +}; + +TEST_F(client_id_utility_test, request_release_client_id) { + app_wrapper app(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x1, app.get_client()); +} + +TEST_F(client_id_utility_test, request_client_id_twice) { + app_wrapper app(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x1, app.get_client()); + + app_wrapper app2(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x2, app2.get_client()); +} + +TEST_F(client_id_utility_test, ensure_sequential_ascending_client_id_allocation) { + app_wrapper app(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x1, app.get_client()); + + auto app2 = std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED); + client_t app2_client = app2->get_client(); + EXPECT_EQ(client_id_base_ | 0x2, app2_client); + + app2.reset(); + + auto app3 = std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED); + client_t app3_client = app3->get_client(); + EXPECT_EQ(client_id_base_ | 0x3, app3_client); + + EXPECT_GT(app3_client, app2_client); + +} + +TEST_F(client_id_utility_test, ensure_preconfigured_client_ids_not_used_for_autoconfig) +{ + // request client ids until 10 over the preconfigured one + const std::uint16_t limit = + static_cast<std::uint16_t>((APPLICATION_IN_CLIENT_ID + & ~diagnosis_mask_) + std::uint16_t(10)); + + std::vector<std::shared_ptr<app_wrapper>> its_apps; + its_apps.reserve(limit); + + for (int i = 0; i < limit; i++ ) { + its_apps.emplace_back( + std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i))); + } + for (const auto& a : its_apps) { + EXPECT_NE(APPLICATION_IN_CLIENT_ID, a->get_client()); + } + its_apps.clear(); +} + +TEST_F(client_id_utility_test, + request_predefined_client_id_in_diagnosis_range) { + auto app1 = std::make_shared<app_wrapper>(APPLICATION_IN_NAME); + EXPECT_EQ(APPLICATION_IN_CLIENT_ID, app1->get_client()); +} + +TEST_F(client_id_utility_test, + request_predefined_client_id_in_diagnosis_range_twice) { + auto app1 = std::make_shared<app_wrapper>(APPLICATION_IN_NAME); + EXPECT_EQ(APPLICATION_IN_CLIENT_ID, app1->get_client()); + + // preconfigured is already taken -> autogenerated ID should be returned + auto app2 = std::make_shared<app_wrapper>(APPLICATION_IN_NAME); + EXPECT_EQ(client_id_base_ | 0x1, app2->get_client()); +} + +TEST_F(client_id_utility_test, + request_predefined_client_id_outside_diagnosis_range_high) { + auto app1 = std::make_shared<app_wrapper>(APPLICATION_OUT_HIGH_NAME); + // we should get the client ID defined in the json file + EXPECT_EQ(APPLICATION_OUT_HIGH_CLIENT_ID, app1->get_client()); +} + +TEST_F(client_id_utility_test, + request_client_id_with_predefined_app_name_outside_diagnosis_range_high_multiple) { + + auto app1 = std::make_shared<app_wrapper>(APPLICATION_OUT_HIGH_NAME); + // we should get the client ID defined in the json file + EXPECT_EQ(APPLICATION_OUT_HIGH_CLIENT_ID, app1->get_client()); + + // preconfigured is already taken -> autogenerated ID should be returned + auto app2 = std::make_shared<app_wrapper>(APPLICATION_OUT_HIGH_NAME); + EXPECT_EQ(client_id_base_ | 0x1, app2->get_client()); + + auto app3 = std::make_shared<app_wrapper>(APPLICATION_OUT_HIGH_NAME); + EXPECT_EQ(client_id_base_ | 0x2, app3->get_client()); +} + +TEST_F(client_id_utility_test, + request_predefined_client_id_outside_diagnosis_range_low) { + auto app1 = std::make_shared<app_wrapper>(APPLICATION_OUT_LOW_NAME); + // we should get the client ID defined in the json file + EXPECT_EQ(APPLICATION_OUT_LOW_CLIENT_ID, app1->get_client()); +} + +TEST_F(client_id_utility_test, + request_predefined_client_id_outside_diagnosis_range_low_multiple) { + auto app1 = std::make_shared<app_wrapper>(APPLICATION_OUT_LOW_NAME); + // we should get the client ID defined in the json file + EXPECT_EQ(APPLICATION_OUT_LOW_CLIENT_ID, app1->get_client()); + + // preconfigured is already taken -> autogenerated ID should be returned + auto app2 = std::make_shared<app_wrapper>(APPLICATION_OUT_LOW_NAME); + EXPECT_EQ(client_id_base_ | 0x1, app2->get_client()); + + auto app3 = std::make_shared<app_wrapper>(APPLICATION_OUT_LOW_NAME); + EXPECT_EQ(client_id_base_ | 0x2, app3->get_client()); +} + +TEST_F(client_id_utility_test, + ensure_preconfigured_client_ids_in_diagnosis_range_dont_influence_autoconfig_client_ids) +{ + auto app0 = std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x1, app0->get_client()); + + auto app1 = std::make_shared<app_wrapper>(APPLICATION_IN_NAME); + EXPECT_EQ(APPLICATION_IN_CLIENT_ID, app1->get_client()); + + auto app2 = std::make_shared<app_wrapper>(APPLICATION_IN_NAME_TWO); + EXPECT_EQ(APPLICATION_IN_CLIENT_ID_TWO, app2->get_client()); + + auto app3 = std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x2, app3->get_client()); + + auto app4 = std::make_shared<app_wrapper>(APPLICATION_NAME_NOT_PREDEFINED); + EXPECT_EQ(client_id_base_ | 0x3, app4->get_client()); +} + +TEST_F(client_id_utility_test, exhaust_client_id_range_sequential) { + std::vector<vsomeip::client_t> its_clients; + std::uint16_t its_max_clients(0); + for (int var = 0; var < __builtin_popcount(static_cast<std::uint16_t>(~diagnosis_mask_)); ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + // -2 as two predefined client IDs are present in the json file which + // aren't assigned via autoconfiguration + const std::uint16_t max_allowed_clients = static_cast<std::uint16_t>(its_max_clients - 2u); + + // acquire maximum amount of client IDs + for (int var = 0; var < 2; ++var) { + for (std::uint16_t i = 0; i < max_allowed_clients; i++) { + const vsomeip::client_t its_client = + vsomeip::utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + if (its_client != VSOMEIP_CLIENT_UNSET) { + if (i > 0) { + EXPECT_LT(its_clients.back(), its_client); + } + its_clients.push_back(its_client); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + // check limit is reached + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, vsomeip::utility::request_client_id( + configuration_, APPLICATION_NAME_NOT_PREDEFINED + "max", + VSOMEIP_CLIENT_UNSET)); + for (const auto c : its_clients) { + utility::release_client_id(configuration_->get_network(), c); + } + } + } + +TEST_F(client_id_utility_test, exhaust_client_id_range_fragmented) { + std::vector<client_t> its_clients; + + // -2 as two predefined client IDs are present in the json file which + // aren't assigned via autoconfiguration + std::uint16_t its_max_clients(0); + for (int var = 0; var < __builtin_popcount(static_cast<std::uint16_t>(~diagnosis_mask_)); ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + const std::uint16_t max_allowed_clients = static_cast<std::uint16_t>(its_max_clients - 2u); + + for (int var = 0; var < 2; ++var) { + // acquire maximum amount of client IDs + for (std::uint16_t i = 0; i < max_allowed_clients; i++) { + const vsomeip::client_t its_client = + vsomeip::utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + if (its_client != VSOMEIP_CLIENT_UNSET) { + if ((var == 0 && i > 0) || + (var == 1 && i > 1) // special case as in the 1st run the last assigned client ID was 63fe + // due to the releases. In the 2nd run the first client ID therefore will be 63ff + ) { + EXPECT_LT(its_clients.back(), its_client); + } + its_clients.push_back(its_client); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // check limit is reached + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, vsomeip::utility::request_client_id( + configuration_, APPLICATION_NAME_NOT_PREDEFINED + "max", + VSOMEIP_CLIENT_UNSET)); + + // release every second requested client ID + std::vector<client_t> its_released_client_ids; + for (size_t i = 0; i < its_clients.size(); i++ ) { + if (i % 2) { + its_released_client_ids.push_back(its_clients[i]); + utility::release_client_id(configuration_->get_network(), its_clients[i]); + } + } + for (const client_t c : its_released_client_ids) { + for (auto it = its_clients.begin(); it != its_clients.end(); ) { + if (*it == c) { + it = its_clients.erase(it); + } else { + ++it; + } + } + } + + // acquire client IDs up to the maximum allowed amount again + for (std::uint16_t i = 0; i < its_released_client_ids.size(); i++) { + const vsomeip::client_t its_client = + vsomeip::utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + if (its_client != VSOMEIP_CLIENT_UNSET) { + if (i > 0) { + EXPECT_LT(its_clients.back(), its_client); + } + its_clients.push_back(its_client); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // check limit is reached + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, vsomeip::utility::request_client_id( + configuration_, APPLICATION_NAME_NOT_PREDEFINED + "max2", + VSOMEIP_CLIENT_UNSET)); + + // release all + for (const auto c : its_clients) { + utility::release_client_id(configuration_->get_network(), c); + } + its_clients.clear(); + } +} + +/* + * @test Check that the autoconfigured client IDs continue to increase even if + * some client IDs at the beginning of the range are already released again + */ +TEST_F(client_id_utility_test, exhaust_client_id_range_fragmented_extended) { + std::vector<client_t> its_client_ids; + + // -1 for the routing manager, -2 as two predefined client IDs are present + // in the json file which aren't assigned via autoconfiguration + std::uint16_t its_max_clients(0); + for (int var = 0; var < __builtin_popcount(static_cast<std::uint16_t>(~diagnosis_mask_)); ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + const std::uint16_t its_diagnosis_mask = configuration_->get_diagnosis_mask(); + const std::uint16_t its_client_mask = static_cast<std::uint16_t>(~its_diagnosis_mask); + const client_t its_masked_diagnosis_address = static_cast<client_t>( + (configuration_->get_diagnosis_address() << 8) & its_diagnosis_mask); + const client_t its_biggest_client = its_masked_diagnosis_address | its_client_mask; + + const std::uint16_t max_possible_clients = its_max_clients; + const std::uint16_t intermediate_release = 3; + const std::uint16_t max_allowed_clients = static_cast<std::uint16_t>(max_possible_clients - 2u); + + // acquire (almost) maximum amount of client IDs + for (std::uint16_t i = 0; i < max_allowed_clients - intermediate_release; i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + if (its_client_id != VSOMEIP_CLIENT_UNSET) { + if (i > 0) { + EXPECT_LT(its_client_ids.back(), its_client_id); + } + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // release the first intermediate_release client IDs again + std::vector<client_t> its_intermediate_released_client_ids; + for (size_t i = 0; i < intermediate_release; i++ ) { + its_intermediate_released_client_ids.push_back(its_client_ids[i]); + utility::release_client_id(configuration_->get_network(), its_client_ids[i]); + its_client_ids.erase(its_client_ids.begin() + i); + } + + // acquire some more client IDs, these should be bigger than the already acquired + for (std::uint16_t i = 0; i < intermediate_release; i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i) + + "intermediate", + VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + if (its_client_id != VSOMEIP_CLIENT_UNSET) { + EXPECT_LT(its_client_ids.back(), its_client_id); + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // check correct wrap around of client IDs + for (std::uint16_t i = 0; i < intermediate_release; i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + if (its_client_id != VSOMEIP_CLIENT_UNSET) { + if (i == 0) { + EXPECT_GT(its_client_ids.back(), its_client_id); + } else { + EXPECT_LT(its_client_ids.back(), its_client_id); + } + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // check limit is reached + client_t its_illegal_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, its_illegal_client_id); + + // release every second requested client ID + std::vector<client_t> its_released_client_ids; + for (size_t i = 0; i < its_client_ids.size(); i++ ) { + if (i % 2) { + its_released_client_ids.push_back(its_client_ids[i]); + utility::release_client_id(configuration_->get_network(), its_client_ids[i]); + } + } + for (const client_t c : its_released_client_ids) { + for (auto it = its_client_ids.begin(); it != its_client_ids.end(); ) { + if (*it == c) { + it = its_client_ids.erase(it); + } else { + ++it; + } + } + } + + // acquire client IDs up to the maximum allowed amount again + for (std::uint16_t i = 0; i < its_released_client_ids.size(); i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED + std::to_string(i), + VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + if (its_client_id != VSOMEIP_CLIENT_UNSET) { + if (i > 0 && its_client_ids.back() != its_biggest_client) { + EXPECT_LT(its_client_ids.back(), its_client_id); + } + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE() << "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // check limit is reached + its_illegal_client_id = 0xFFFF; + its_illegal_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, its_illegal_client_id); + + // release all + for (const client_t c : its_client_ids) { + utility::release_client_id(configuration_->get_network(), c); + } +} + +TEST_F(client_id_utility_test, request_released_client_id_after_maximum_client_id_is_assigned) { + std::vector<client_t> its_client_ids; + std::uint16_t its_max_clients(0); + for (int var = 0; var < __builtin_popcount(static_cast<std::uint16_t>(~diagnosis_mask_)); ++var) { + its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var)); + } + const std::uint16_t max_possible_clients = its_max_clients; + // -1 for the routing manager, -2 as two predefined client IDs are present + // in the json file which aren't assigned via autoconfiguration + const std::uint16_t max_allowed_clients = static_cast<std::uint16_t>(max_possible_clients - 2u); + + // acquire (almost) maximum amount of client IDs + for (std::uint16_t i = 0; i < max_allowed_clients - 1; i++) { + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + if (its_client_id != VSOMEIP_CLIENT_UNSET) { + if (i > 0) { + EXPECT_LT(its_client_ids.back(), its_client_id); + } + its_client_ids.push_back(its_client_id); + } else { + ADD_FAILURE()<< "Received VSOMEIP_CLIENT_UNSET " + << static_cast<std::uint32_t>(i); + } + } + + // release a client ID + utility::release_client_id(configuration_->get_network(), its_client_ids[10]); + + // requesting an ID should return the maximum possible ID + client_t its_max_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_max_client_id); + its_client_ids.push_back(its_max_client_id); + + // requesting an ID should work as we have released one before + client_t its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + its_client_ids.push_back(its_client_id); + + // requesting an ID should not work as all IDs are in use now + client_t its_illegal_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_EQ(VSOMEIP_CLIENT_UNSET, its_illegal_client_id); + + // release another ID + utility::release_client_id(configuration_->get_network(), its_client_ids[5]); + + its_client_id = utility::request_client_id(configuration_, + APPLICATION_NAME_NOT_PREDEFINED, VSOMEIP_CLIENT_UNSET); + EXPECT_NE(VSOMEIP_CLIENT_UNSET, its_client_id); + its_client_ids.push_back(its_client_id); + + // release all + for (const client_t c : its_client_ids) { + utility::release_client_id(configuration_->get_network(), c); + } + its_client_ids.clear(); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..b064cb31a4b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_master.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_one", + "id":"0x1111" + }, + { + "name":"client_id_test_service_two", + "id":"0x2222" + }, + { + "name":"client_id_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..a743e5c9403 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_diff_ports_slave.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_four", + "id":"0x4444" + }, + { + "name":"client_id_test_service_five", + "id":"0x5555" + }, + { + "name":"client_id_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4000", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5000", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6000", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in new file mode 100644 index 00000000000..f7e5a472212 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_master.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_one", + "id":"0x1111" + }, + { + "name":"client_id_test_service_two", + "id":"0x2222" + }, + { + "name":"client_id_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in new file mode 100644 index 00000000000..48dbf5f5878 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_partial_same_ports_slave.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_four", + "id":"0x4444" + }, + { + "name":"client_id_test_service_five", + "id":"0x5555" + }, + { + "name":"client_id_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4000", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5000", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6000", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..d606e96f77f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_master.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_one", + "id":"0x1111" + }, + { + "name":"client_id_test_service_two", + "id":"0x2222" + }, + { + "name":"client_id_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..9563b2a4f17 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_diff_client_ids_same_ports_slave.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_four", + "id":"0x4444" + }, + { + "name":"client_id_test_service_five", + "id":"0x5555" + }, + { + "name":"client_id_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_master_starter.sh.in new file mode 100755 index 00000000000..25b66229a4d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_master_starter.sh.in @@ -0,0 +1,80 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 client_id_test_diff_client_ids_diff_ports_master.json" + exit 1 +fi + +MASTER_JSON_FILE=$1 +CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave} + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=client_id_test_service_one +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 1 & +CLIENT_ID_PIDS[1]=$! + +export VSOMEIP_APPLICATION_NAME=client_id_test_service_two +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 2 & +CLIENT_ID_PIDS[2]=$! + +export VSOMEIP_APPLICATION_NAME=client_id_test_service_three +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 3 & +CLIENT_ID_PIDS[3]=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting client id test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/client_id_tests; ./client_id_test_slave_starter.sh $CLIENT_JSON_FILE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./client_id_test_slave_starter.sh $CLIENT_JSON_FILE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** client_id_test_slave_starter.sh $CLIENT_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** client_id_test_diff_client_ids_diff_ports_master.json and +** client_id_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for client_pid in "${CLIENT_ID_PIDS[@]}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..b064cb31a4b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_master.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_one", + "id":"0x1111" + }, + { + "name":"client_id_test_service_two", + "id":"0x2222" + }, + { + "name":"client_id_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..2f392415bcf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_diff_ports_slave.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_four", + "id":"0x1111" + }, + { + "name":"client_id_test_service_five", + "id":"0x2222" + }, + { + "name":"client_id_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4000", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5000", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6000", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..d606e96f77f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_master.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_one", + "id":"0x1111" + }, + { + "name":"client_id_test_service_two", + "id":"0x2222" + }, + { + "name":"client_id_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..2335195a050 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_same_client_ids_same_ports_slave.json.in @@ -0,0 +1,70 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"client_id_test_service_four", + "id":"0x1111" + }, + { + "name":"client_id_test_service_five", + "id":"0x2222" + }, + { + "name":"client_id_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6000", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"client_id_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_slave_starter.sh.in new file mode 100755 index 00000000000..fbdfe5c06a2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_slave_starter.sh.in @@ -0,0 +1,50 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 client_id_test_diff_client_ids_diff_ports_slave.json" + exit 1 +fi + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=client_id_test_service_four +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 4 & + +export VSOMEIP_APPLICATION_NAME=client_id_test_service_five +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 5 & + +export VSOMEIP_APPLICATION_NAME=client_id_test_service_six +export VSOMEIP_CONFIGURATION=$1 +./client_id_test_service 6 & + + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility.json.in new file mode 100644 index 00000000000..e07eb9afc2d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility.json.in @@ -0,0 +1,35 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6311" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6312" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"routingmanagerd" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_discontinuous_masked_511.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_discontinuous_masked_511.json.in new file mode 100644 index 00000000000..af3dfd6c54f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_discontinuous_masked_511.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "diagnosis_mask":"0xFB00", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6311" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6312" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"routingmanagerd" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_127.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_127.json.in new file mode 100644 index 00000000000..8aa51353b0a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_127.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x63", + "diagnosis_mask":"0xFF80", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6311" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6312" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"routingmanagerd" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_4095.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_4095.json.in new file mode 100644 index 00000000000..86044350b35 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_4095.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x60", + "diagnosis_mask":"0xF000", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6011" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6012" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"routingmanagerd" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_511.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_511.json.in new file mode 100644 index 00000000000..a57d382a461 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/client_id_tests/conf/client_id_test_utility_masked_511.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"false" + }, + "diagnosis":"0x62", + "diagnosis_mask":"0xFE00", + "applications": + [ + { + "name":"client_id_test_utility_service_in", + "id":"0x6211" + }, + { + "name":"client_id_test_utility_service_in_two", + "id":"0x6212" + }, + { + "name":"client_id_test_utility_service_out_low", + "id":"0x5911" + }, + { + "name":"client_id_test_utility_service_out_high", + "id":"0x7411" + } + ], + "routing":"routingmanagerd" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/CMakeLists.txt new file mode 100644 index 00000000000..c570f317760 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(configuration_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + configuration_test_deprecated.json + configuration_test.json +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(configuration_test + configuration_test.cpp +) + +# Link vsomeip configuration libraries. +target_link_libraries(configuration_test + ${VSOMEIP_NAME}-cfg +) + +# Add build dependencies and link libraries to executable. +targets_link_default_libraries(configuration_test) +targets_add_default_dependencies(configuration_test) + +# Add custom test command. +add_custom_test( + NAME configuration_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/configuration_test +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test.json.in new file mode 100644 index 00000000000..6ee9168b8dd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test.json.in @@ -0,0 +1,533 @@ +{ + "unicast" : "10.0.2.15", + "diagnosis" : "0x55", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "true", "path" : "/home/someip/another-file.log" }, + "dlt" : "false", + "version" : { + "enable" : "false", + "interval" : "15" + } + }, + "watchdog" : + { + "enable" : "true", + "timeout" : "1234", + "allowed_missing_pongs" : "7" + }, + "file-permissions" : + { + "permissions-shm" : "0444", + "permissions-uds" : "0222" + }, + "supports_selective_broadcasts" : + [ + "160.160.160.160" + ], + "tracing" : + { + "enable" : "true", + "sd_enable" : "true", + "channels" : + [ + { + "name" : "testname", + "id" : "testid" + }, + { + "name" : "testname2", + "id" : "testid2" + }, + { + "name" : "testname3", + "id" : "testid3" + }, + { + "name" : "testname4", + "id" : "testid4" + } + ], + "filters" : + [ + { + "channel" : "testname", + "matches" : [ "0x1111", 2222 ], + "type" : "positive" + }, + { + "channel" : "testname2", + "matches" : [ "0x3333", 4444 ], + "type" : "negative" + }, + { + "channel" : "testname3", + "matches" : [ "0x1111", { "service" : "0x3333", "instance" : "0xffff", "method" : "0x8888" } ], + "type" : "negative" + }, + { + "channel" : "testname4", + "matches" : + { + "from" : + { + "service" : "0x1111", + "instance" : "0x0001", + "method" : "0xffff" + }, + "to" : + { + "service" : "0x3333", + "instance" : "0x0001", + "method" : "0x8888" + } + }, + "type" : "negative" + } + ] + }, + "applications" : + [ + { + "name" : "my_application", + "id" : "0x7788", + "max_dispatchers" : "25", + "max_dispatch_time" : "1234", + "max_detached_thread_wait_time":"3", + "threads" : "12", + "request_debounce_time" : "5000", + "plugins" : + [ + { + "name" : "testlibraryname", + "type" : "application_plugin" + }, + { + "name" : "wrongtestlibraryname", + "type" : "intentionally_wrong_plugin" + } + ] + }, + { + "name" : "other_application", + "id" : "0x9933", + "threads" : "0", + "threads" : "256", + "request_debounce_time" : "10001" + } + ], + "suppress_missing_event_logs" : + [ + { + "service" : "0x0023", + "instance" : "0x0001", + "events" : [ "0x8001", "0x8002", + { + "first" : "0x8010", + "last" : "0x8015" + }, + "0x8020" ] + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : "0x8005" + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : [ "0x8105", "0x8106" ] + }, + { + "service" : "any", + "instance" : "0x00f2" + }, + { + "service" : "0x0102", + "instance" : "any", + "events" : [ "0x8005", "0x8006" ] + }, + { + "service" : "0x24", + "instance" : "any", + "events" : { + "first" : "0x8010", + "last" : "0x8015" + } + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x0022", + "unicast" : "local", + "reliable" : { "port" : "30506", "enable-magic-cookies" : "true" }, + "unreliable" : "31000", + "events" : + [ + { + "event" : "0x0778", + "is_field" : "false" + }, + { + "event" : "0x779", + "is_field" : "true" + }, + { + "event" : "0x77A", + "is_field" : "false" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4567", + "multicast" : "225.226.227.228", + "events" : [ "0x778", "0x779" ] + }, + { + "eventgroup" : "0x4569", + "multicast" : "225.227.227.228", + "events" : [ "0x779", "0x77A" ] + }, + { + "eventgroup" : "0x4569", + "multicast" : "225.222.227.228", + "events" : [ "0x778", "0x77A" ] + } + ] + }, + { + "service" : "0x1234", + "instance" : "0x0023", + "reliable" : "30503" + }, + { + "service" : "0x2277", + "instance" : "0x0022", + "reliable" : { "port" : "30505" }, + "unreliable" : "31001" + }, + { + "service" : "0x2266", + "instance" : "0x0022", + "reliable" : "30505", + "unreliable" : "30507" + }, + { + "service" : "0x4466", + "instance" : "0x0321", + "unicast" : "10.0.2.23", + "reliable" : "30506", + "unreliable" : "30444" + }, + { + "service" : "0x3333", + "instance" : "0x1" + }, + { + "service" : "0x7809", + "instance" : "0x1", + "multicast" : + { + "address" : "224.212.244.225", + "port" : "1234" + }, + "eventgroups" : + [ + { + "eventgroup" : "0x1111", + "threshold" : "8", + "is_multicast" : "true", + "events" : [ "0x778", "0x77A" ] + } + ] + }, + { + "service" : "0x3555", + "instance" : "0x1", + "protocol" : "other" + } + ], + "internal_services" : + [ + { + "first" : "0xF100", + "last" : "0xF109" + }, + { + "first" : { + "service" : "0xF300", + "instance" : "0x1" + }, + "last" : { + "service" : "0xF300", + "instance" : "0x10" + } + } + ], + "clients" : + [ + { + "reliable_remote_ports" : { "first" : "30500", "last" : "30599" }, + "unreliable_remote_ports" : { "first" : "30500", "last" : "30599" }, + "reliable_client_ports" : { "first" : "30491", "last" : "30499" }, + "unreliable_client_ports" : { "first" : "30491", "last" : "30499" } + }, + { + "reliable_remote_ports" : { "first" : "31500", "last" : "31599" }, + "unreliable_remote_ports" : { "first" : "31500", "last" : "31599" }, + "reliable_client_ports" : { "first" : "31491", "last" : "31499" }, + "unreliable_client_ports" : { "first" : "31491", "last" : "31499" } + }, + { + "reliable_remote_ports" : { "first" : "32500", "last" : "32599" }, + "unreliable_remote_ports" : { "first" : "32500", "last" : "32599" }, + "reliable_client_ports" : { "first" : "32491", "last" : "32499" }, + "unreliable_client_ports" : { "first" : "32491", "last" : "32499" } + }, + { + "service" : "0x8888", + "instance" : "0x1", + "unreliable" : [ "0x11", "0x10" ], + "reliable" : [ "0x11", "0x10" ] + }, + { + "service" : "8888", + "instance" : "1", + "unreliable" : [ 40000, 40001 ], + "reliable" : [ 40000, 40001 ] + } + ], + "tcp-restart-aborts-max" : "15", + "tcp-connect-time-max" : "10000", + "max-payload-size-local" : "15000", + "max-payload-size-reliable" : "17000", + "buffer-shrink-threshold" : "11", + "payload-sizes": + [ + { + "unicast":"10.10.10.10", + "ports": + [ + { + "port":"7777", + "max-payload-size":"14999" + } + ] + }, + { + "unicast":"10.10.10.11", + "ports": + [ + { + "port":"7778", + "max-payload-size":"15001" + } + ] + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + }, + { + "service" : "0x1236", + "instances" : [{ "first" : "0x5676", "last" : "0x5677"}, "0x5678"] + } + ] + } + }, + { + "credentials" : { "uid" : "2000", "gid" : "2000" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678", { "first" : "0x5679", "last" : "0x5699"}], + "methods" : [ "0x0001", { "first" : "0x8001", "last" : "0x8006" }] + } + ] + }, + { + "service" : "0x1237", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + }, + { + "service" : "0x1238", + "instances" : [ + { + "ids" : "any", + "methods" : ["0x0001"] + } + ] + } + ] + } + }, + { + "credentials" : { "uid" : "4000", "gid" : "4000" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678", { "first" : "0x5679", "last" : "0x5699"}], + "methods" : [ "0x0002", { "first" : "0x9001", "last" : "0x9006" }] + } + ] + } + ], + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + }, + { + "service" : "0x1236", + "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"] + } + ] + } + }, + { + "credentials" : { "uid" : "5000", "gid" : "5000" }, + "deny" : + { + } + }, + { + "credentials" : { "uid" : "6000", "gid" : "6000" }, + "allow" : + { + } + }, + { + "credentials" : { "uid" : "7000", "gid" : "7000" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + } + ] + } + }, + { + "credentials" : { "uid" : "8000", "gid" : "8000" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + } + ] + } + }, + { + "credentials" : { + "allow": [ + { + "uid": [ + "9000" + ], + "gid": [ + "9000" + ] + } + ] + }, + "deny" : + { + } + } + ] + }, + "security-update-whitelist" : + { + "uids" : + [ + {"first" : "1000", "last" : "1008"}, + {"first" : "1100", "last" : "1200"}, + "2000", + "3000" + ], + "services" : + [ + {"first" : "0x1234", "last" : "0x1238"}, + {"first" : "0x2000", "last" : "0x2500"}, + "0x7800" + ], + "check-whitelist" : "true" + }, + "routing" : "my_application", + "routing-credentials" : + { + "uid" : "0x123", + "gid" : "0x456" + }, + "service-discovery" : + { + "enable" : "true", + "protocol" : "udp", + "multicast" : "224.212.244.223", + "port" : "30666", + "initial_delay_min" : "1234", + "initial_delay_max" : "2345", + "repetitions_base_delay" : "4242", + "repetitions_max" : "4", + "ttl" : "13", + "cyclic_offer_delay" : "2132", + "request_response_delay" : "1111", + "offer_debounce_time" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test_deprecated.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test_deprecated.json.in new file mode 100644 index 00000000000..a6cc993c84d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/conf/configuration_test_deprecated.json.in @@ -0,0 +1,537 @@ +{ + "unicast" : "10.0.2.15", + "diagnosis" : "85", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "true", "path" : "/home/someip/another-file.log" }, + "dlt" : "false", + "version" : { + "enable" : "false", + "interval" : "15" + } + }, + "watchdog" : + { + "enable" : "true", + "timeout" : "1234", + "allowed_missing_pongs" : "7" + }, + "file-permissions" : + { + "permissions-shm" : "444", + "permissions-uds" : "222" + }, + "supports_selective_broadcasts" : + { + "address" : "160.160.160.160" + }, + "tracing" : + { + "enable" : "true", + "sd_enable" : "true", + "channels" : + [ + { + "name" : "testname", + "id" : "testid" + }, + { + "name" : "testname2", + "id" : "testid2" + }, + { + "name" : "testname3", + "id" : "testid3" + }, + { + "name" : "testname4", + "id" : "testid4" + } + ], + "filters" : + [ + { + "channel" : "testname", + "services" : ["0x1111",2222], + "type" : "positive" + }, + { + "channel" : "testname2", + "services" : ["0x3333",4444], + "type" : "negative" + } + ] + }, + "applications" : + [ + { + "name" : "my_application", + "id" : "0x7788", + "max_dispatchers" : "25", + "max_dispatch_time" : "1234", + "max_detached_thread_wait_time":"3", + "threads" : "12", + "request_debounce_time" : "5000", + "plugins" : + [ + { + "application_plugin" : "testlibraryname" + }, + { + "intentionally_wrong_plugin" : "wrong" + } + ] + }, + { + "name" : "other_application", + "id" : "0x9933", + "threads" : "0", + "threads" : "256", + "request_debounce_time" : "10001" + } + ], + "suppress_missing_event_logs" : + [ + { + "service" : "0x0023", + "instance" : "0x0001", + "events" : [ "0x8001", "0x8002", + { + "first" : "0x8010", + "last" : "0x8015" + }, + "0x8020" ] + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : "0x8005" + }, + { + "service" : "0x0023", + "instance" : "0x0002", + "events" : [ "0x8105", "0x8106" ] + }, + { + "service" : "any", + "instance" : "0x00f2" + }, + { + "service" : "0x0102", + "instance" : "any", + "events" : [ "0x8005", "0x8006" ] + }, + { + "service" : "0x24", + "instance" : "any", + "events" : { + "first" : "0x8010", + "last" : "0x8015" + } + } + ], + "servicegroups" : + [ + { + "name" : "default", + "unicast" : "local", + "delays" : + { + "initial" : { "minimum" : "10", "maximum" : "100" }, + "repetition-base" : "200", + "repetition-max" : "7", + "cyclic-offer" : "2132", + "cyclic-request" : "2001", + "ttl" : "5" + }, + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x0022", + "reliable" : { "port" : "30506", "enable-magic-cookies" : "true" }, + "unreliable" : "31000", + "events" : + [ + { + "event" : "0x0778", + "is_field" : "false" + }, + { + "event" : "0x779", + "is_field" : "true" + }, + { + "event" : "0x77A", + "is_field" : "false" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4567", + "multicast" : "225.226.227.228", + "events" : [ "0x778", "0x779" ] + }, + { + "eventgroup" : "0x4569", + "multicast" : "225.227.227.228", + "events" : [ "0x779", "0x77A" ] + }, + { + "eventgroup" : "0x4569", + "multicast" : "225.222.227.228", + "events" : [ "0x778", "0x77A" ] + } + ] + }, + { + "service" : "0x1234", + "instance" : "0x0023", + "reliable" : "30503" + }, + { + "service" : "0x7809", + "instance" : "0x1", + "multicast" : + { + "address" : "224.212.244.225", + "port" : "1234" + }, + "eventgroups" : + [ + { + "eventgroup" : "0x1111", + "threshold" : "8", + "is_multicast" : "true", + "events" : [ "0x778", "0x77A" ] + } + ] + } + ] + }, + { + "name" : "extra", + "unicast" : "local", + "delays" : + { + "initial" : { "minimum" : "10", "maximum" : "100" }, + "repetition-base" : "200", + "repetition-max" : "7", + "cyclic-offer" : "2132", + "cyclic-request" : "2001", + "ttl" : "5" + }, + "services" : + [ + { + "service" : "0x2277", + "instance" : "0x0022", + "reliable" : { "port" : "30505" }, + "unreliable" : "31001" + }, + { + "service" : "0x2266", + "instance" : "0x0022", + "reliable" : "30505", + "unreliable" : "30507" + }, + { + "service" : "0x3333", + "instance" : "0x1" + }, + { + "service" : "0x3555", + "instance" : "0x1", + "protocol" : "other" + } + ] + }, + { + "name" : "remote", + "unicast" : "10.0.2.23", + "services" : + [ + { + "service" : "0x4466", + "instance" : "0x0321", + "reliable" : "30506", + "unreliable" : "30444" + } + ] + } + ], + "internal_services" : + [ + { + "first" : "0xF100", + "last" : "0xF109" + }, + { + "first" : { + "service" : "0xF300", + "instance" : "0x1" + }, + "last" : { + "service" : "0xF300", + "instance" : "0x10" + } + } + ], + "clients" : + [ + { + "reliable_remote_ports" : { "first" : "30500", "last" : "30599" }, + "unreliable_remote_ports" : { "first" : "30500", "last" : "30599" }, + "reliable_client_ports" : { "first" : "30491", "last" : "30499" }, + "unreliable_client_ports" : { "first" : "30491", "last" : "30499" } + }, + { + "reliable_remote_ports" : { "first" : "31500", "last" : "31599" }, + "unreliable_remote_ports" : { "first" : "31500", "last" : "31599" }, + "reliable_client_ports" : { "first" : "31491", "last" : "31499" }, + "unreliable_client_ports" : { "first" : "31491", "last" : "31499" } + }, + { + "reliable_remote_ports" : { "first" : "32500", "last" : "32599" }, + "unreliable_remote_ports" : { "first" : "32500", "last" : "32599" }, + "reliable_client_ports" : { "first" : "32491", "last" : "32499" }, + "unreliable_client_ports" : { "first" : "32491", "last" : "32499" } + }, + { + "service" : "0x8888", + "instance" : "0x1", + "unreliable" : [ "0x11", "0x10" ], + "reliable" : [ "0x11", "0x10" ] + }, + { + "service" : "8888", + "instance" : "1", + "unreliable" : [ 40000, 40001 ], + "reliable" : [ 40000, 40001 ] + } + ], + "tcp-restart-aborts-max" : "15", + "tcp-connect-time-max" : "10000", + "max-payload-size-local" : "15000", + "max-payload-size-reliable" : "17000", + "buffer-shrink-threshold" : "11", + "payload-sizes": + [ + { + "unicast":"10.10.10.10", + "ports": + [ + { + "port":"7777", + "max-payload-size":"14999" + } + ] + }, + { + "unicast":"10.10.10.11", + "ports": + [ + { + "port":"7778", + "max-payload-size":"15001" + } + ] + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "credentials" : { "uid" : "1000", "gid" : "1000" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + }, + { + "service" : "0x1236", + "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"] + } + ] + } + }, + { + "credentials" : { "uid" : "2000", "gid" : "2000" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678", { "first" : "0x5679", "last" : "0x5699"}], + "methods" : [ "0x0001", { "first" : "0x8001", "last" : "0x8006" }] + } + ] + }, + { + "service" : "0x1237", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + }, + { + "service" : "0x1238", + "instances" : [ + { + "ids" : "any", + "methods" : ["0x0001"] + } + ] + } + ] + } + }, + { + "credentials" : { "uid" : "4000", "gid" : "4000" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678", { "first" : "0x5679", "last" : "0x5699"}], + "methods" : [ "0x0002", { "first" : "0x9001", "last" : "0x9006" }] + } + ] + } + ], + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + }, + { + "service" : "0x1235", + "instance" : "0x5678" + }, + { + "service" : "0x1236", + "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"] + } + ] + } + }, + { + "credentials" : { "uid" : "5000", "gid" : "5000" }, + "deny" : + { + } + }, + { + "credentials" : { "uid" : "6000", "gid" : "6000" }, + "allow" : + { + } + }, + { + "credentials" : { "uid" : "7000", "gid" : "7000" }, + "deny" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + } + ] + } + }, + { + "credentials" : { "uid" : "8000", "gid" : "8000" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : [ + { + "ids" : ["0x5678"], + "methods" : "any" + } + ] + } + ] + } + }, + { + "credentials" : { + "allow": [ + { + "uid": [ + "9000" + ], + "gid": [ + "9000" + ] + } + ] + }, + "deny" : + { + } + } + ] + }, + "security-update-whitelist" : + { + "uids" : + [ + {"first" : "1000", "last" : "1008"}, + {"first" : "1100", "last" : "1200"}, + "2000", + "3000" + ], + "services" : + [ + {"first" : "0x1234", "last" : "0x1238"}, + {"first" : "0x2000", "last" : "0x2500"}, + "0x7800" + ], + "check-whitelist" : "true" + }, + "routing" : "my_application", + "routing-credentials" : + { + "uid" : "0x123", + "gid" : "0x456" + }, + "service-discovery" : + { + "enable" : "true", + "protocol" : "udp", + "multicast" : "224.212.244.223", + "port" : "30666", + "offer_debounce_time" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/configuration_test.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/configuration_test.cpp new file mode 100644 index 00000000000..68e017e3715 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/configuration_tests/configuration_test.cpp @@ -0,0 +1,856 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstdlib> +#include <iostream> + +#include <gtest/gtest.h> + +#include <common/utility.hpp> + +#include <vsomeip/constants.hpp> +#include <vsomeip/plugins/application_plugin.hpp> +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/internal/plugin_manager.hpp> +#include "../implementation/configuration/include/configuration.hpp" + +#include "../../implementation/configuration/include/configuration_impl.hpp" +#include "../../implementation/configuration/include/configuration_plugin.hpp" +#include "../../implementation/protocol/include/protocol.hpp" +#include "../../implementation/security/include/policy_manager_impl.hpp" + +namespace vsomeip = vsomeip_v3; + +#define CONFIGURATION_FILE "configuration_test.json" +#define DEPRECATED_CONFIGURATION_FILE "configuration_test_deprecated.json" + +#define EXPECTED_UNICAST_ADDRESS "10.0.2.15" + +#define EXPECTED_HAS_CONSOLE true +#define EXPECTED_HAS_FILE true +#define EXPECTED_HAS_DLT false +#define EXPECTED_LOGLEVEL "debug" +#define EXPECTED_LOGFILE "/home/someip/another-file.log" + +#define EXPECTED_ROUTING_MANAGER_HOST "my_application" + +// Logging +#define EXPECTED_VERSION_LOGGING_ENABLED false +#define EXPECTED_VERSION_LOGGING_INTERVAL 15 + +// Application +#define EXPECTED_APPLICATION_MAX_DISPATCHERS 25 +#define EXPECTED_APPLICATION_MAX_DISPATCH_TIME 1234 +#define EXPECTED_APPLICATION_MAX_DETACHED_THREAD_WAIT_TIME 3 +#define EXPECTED_APPLICATION_THREADS 12 +#define EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME 5000 + +// Services +#define EXPECTED_UNICAST_ADDRESS_1234_0022 EXPECTED_UNICAST_ADDRESS +#define EXPECTED_RELIABLE_PORT_1234_0022 30506 +#define EXPECTED_UNRELIABLE_PORT_1234_0022 31000 + +#define EXPECTED_UNICAST_ADDRESS_1234_0023 EXPECTED_UNICAST_ADDRESS +#define EXPECTED_RELIABLE_PORT_1234_0023 30503 +#define EXPECTED_UNRELIABLE_PORT_1234_0023 vsomeip::ILLEGAL_PORT + +#define EXPECTED_UNICAST_ADDRESS_2277_0022 EXPECTED_UNICAST_ADDRESS +#define EXPECTED_RELIABLE_PORT_2277_0022 30505 +#define EXPECTED_UNRELIABLE_PORT_2277_0022 31001 + +#define EXPECTED_UNICAST_ADDRESS_2266_0022 EXPECTED_UNICAST_ADDRESS +#define EXPECTED_RELIABLE_PORT_2266_0022 30505 +#define EXPECTED_UNRELIABLE_PORT_2266_0022 30507 + +#define EXPECTED_UNICAST_ADDRESS_4466_0321 "10.0.2.23" +#define EXPECTED_RELIABLE_PORT_4466_0321 30506 +#define EXPECTED_UNRELIABLE_PORT_4466_0321 30444 + +// Service Discovery +#define EXPECTED_SD_ENABLED true +#define EXPECTED_SD_PROTOCOL "udp" +#define EXPECTED_SD_MULTICAST "224.212.244.223" +#define EXPECTED_SD_PORT 30666 + +#define EXPECTED_INITIAL_DELAY_MIN 1234 +#define EXPECTED_INITIAL_DELAY_MAX 2345 +#define EXPECTED_REPETITIONS_BASE_DELAY 4242 +#define EXPECTED_REPETITIONS_MAX 4 +#define EXPECTED_TTL 13 +#define EXPECTED_CYCLIC_OFFER_DELAY 2132 +#define EXPECTED_REQUEST_RESPONSE_DELAY 1111 + +#define EXPECTED_DEPRECATED_INITIAL_DELAY_MIN 10 +#define EXPECTED_DEPRECATED_INITIAL_DELAY_MAX 100 +#define EXPECTED_DEPRECATED_REPETITIONS_BASE_DELAY 200 +#define EXPECTED_DEPRECATED_REPETITIONS_MAX 7 +#define EXPECTED_DEPRECATED_TTL 5 +#define EXPECTED_DEPRECATED_REQUEST_RESPONSE_DELAY 2001 + +template<class T> +::testing::AssertionResult check(const T &_is, const T &_expected, const std::string &_test) { + if (_is == _expected) { + return ::testing::AssertionSuccess() << "Test \"" << _test << "\" succeeded."; + } else { + return ::testing::AssertionFailure() << "Test \"" << _test << "\" failed! (" + << _is << " != " << _expected << ")"; + } +} + +std::string loglevel_to_string(vsomeip::logger::level_e &_level) { + switch (_level) { + case vsomeip::logger::level_e::LL_FATAL: + return "fatal"; + case vsomeip::logger::level_e::LL_ERROR: + return "error"; + case vsomeip::logger::level_e::LL_WARNING: + return "warning"; + case vsomeip::logger::level_e::LL_INFO: + return "info"; + case vsomeip::logger::level_e::LL_DEBUG: + return "debug"; + case vsomeip::logger::level_e::LL_VERBOSE: + return "verbose"; + default: + return "unknown"; + } +} + +void check_file(const std::string &_config_file, + const std::string &_expected_unicast_address, + bool _expected_has_console, + bool _expected_has_file, + bool _expected_has_dlt, + bool _expected_version_logging_enabled, + uint32_t _expected_version_logging_interval, + uint32_t _expected_application_max_dispatcher, + uint32_t _expected_application_max_dispatch_time, + uint32_t _expected_application_max_detached_thread_wait_time, + uint32_t _expected_application_threads, + uint32_t _expected_application_request_debounce_time, + const std::string &_expected_logfile, + const std::string &_expected_loglevel, + const std::string &_expected_unicast_address_1234_0022, + uint16_t _expected_reliable_port_1234_0022, + uint16_t _expected_unreliable_port_1234_0022, + const std::string &_expected_unicast_address_1234_0023, + uint16_t _expected_reliable_port_1234_0023, + uint16_t _expected_unreliable_port_1234_0023, + const std::string &_expected_unicast_address_2277_0022, + uint16_t _expected_reliable_port_2277_0022, + uint16_t _expected_unreliable_port_2277_0022, + const std::string &_expected_unicast_address_2266_0022, + uint16_t _expected_reliable_port_2266_0022, + uint16_t _expected_unreliable_port_2266_0022, + const std::string &_expected_unicast_address_4466_0321, + uint16_t _expected_reliable_port_4466_0321, + uint16_t _expected_unreliable_port_4466_0321, + bool _expected_enabled, + const std::string &_expected_protocol, + const std::string &_expected_multicast, + uint16_t _expected_port, + uint32_t _expected_initial_delay_min, + uint32_t _expected_initial_delay_max, + int32_t _expected_repetitions_base_delay, + uint8_t _expected_repetitions_max, + vsomeip::ttl_t _expected_ttl, + vsomeip::ttl_t _expected_cyclic_offer_delay, + vsomeip::ttl_t _expected_request_response_delay) { + + + // 0. Set environment variable to config file and load it +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) + setenv("VSOMEIP_CONFIGURATION", _config_file.c_str(), 1); +#else + _putenv_s("VSOMEIP_CONFIGURATION", _config_file.c_str() +#endif + + // 1. Create configuration object + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_configuration_plugin + = std::dynamic_pointer_cast<vsomeip::configuration_plugin>(its_plugin); + if (its_configuration_plugin) + its_configuration = its_configuration_plugin->get_configuration(EXPECTED_ROUTING_MANAGER_HOST, ""); + } + + // 2. Did we get a configuration object? + if (0 == its_configuration) { + ADD_FAILURE() << "No configuration object. " + "Either memory overflow or loading error detected!"; + return; + } + + // Check "suppress_missing_event_logs" + EXPECT_TRUE(its_configuration->check_suppress_events(0x0023, 0x0001, 0x8002)); // Multiple values + EXPECT_TRUE(its_configuration->check_suppress_events(0x0023, 0x0001, 0x8015)); // Range + EXPECT_FALSE(its_configuration->check_suppress_events(0x0023, 0x0001, 0x8016)); // Range + EXPECT_TRUE(its_configuration->check_suppress_events(0x0023, 0x0001, 0x8020)); // Single + + EXPECT_TRUE(its_configuration->check_suppress_events(0x0023, 0x0002, 0x8005)); // Single + EXPECT_FALSE(its_configuration->check_suppress_events(0x0023, 0x0002, 0x8006)); // Single + + EXPECT_TRUE(its_configuration->check_suppress_events(0x1111, 0x00f2, 0x8001)); // "ANY" Service/Event + EXPECT_TRUE(its_configuration->check_suppress_events(0x0102, 0x0010, 0x8005)); // "ANY" Instance + EXPECT_FALSE(its_configuration->check_suppress_events(0x0102, 0x0010, 0x8007)); // "ANY" Instance + + EXPECT_TRUE(its_configuration->check_suppress_events(0x0024, 0x5555, 0x8011)); // "ANY" INSTANCE + EXPECT_FALSE(its_configuration->check_suppress_events(0x0024, 0x5555, 0x8016)); // "ANY" INSTANCE + + vsomeip::cfg::configuration_impl its_copied_config( + static_cast<vsomeip::cfg::configuration_impl&>(*its_configuration)); + vsomeip::cfg::configuration_impl* its_new_config = + new vsomeip::cfg::configuration_impl(its_copied_config); + delete its_new_config; + + its_configuration->set_configuration_path("/my/test/path"); + + // 3. Check host address + boost::asio::ip::address its_host_unicast_address + = its_configuration->get_unicast_address(); + EXPECT_TRUE(check<std::string>(its_host_unicast_address.to_string(), + _expected_unicast_address, "UNICAST ADDRESS")); + EXPECT_TRUE(its_configuration->is_v4()); + EXPECT_FALSE(its_configuration->is_v6()); + + // check diagnosis prefix + EXPECT_NE(0x54, its_configuration->get_diagnosis_address()); + EXPECT_EQ(0x55, its_configuration->get_diagnosis_address()); + EXPECT_NE(0x56, its_configuration->get_diagnosis_address()); + + // 4. Check logging + bool has_console = its_configuration->has_console_log(); + bool has_file = its_configuration->has_file_log(); + bool has_dlt = its_configuration->has_dlt_log(); + std::string logfile = its_configuration->get_logfile(); + vsomeip::logger::level_e loglevel + = its_configuration->get_loglevel(); + bool has_version_logging = its_configuration->log_version(); + std::uint32_t version_logging_interval = its_configuration->get_log_version_interval(); + + EXPECT_TRUE(check<bool>(has_console, _expected_has_console, "HAS CONSOLE")); + EXPECT_TRUE(check<bool>(has_file, _expected_has_file, "HAS FILE")); + EXPECT_TRUE(check<bool>(has_dlt, _expected_has_dlt, "HAS DLT")); + EXPECT_TRUE(check<std::string>(logfile, _expected_logfile, "LOGFILE")); + EXPECT_TRUE(check<std::string>(loglevel_to_string(loglevel), + _expected_loglevel, "LOGLEVEL")); + EXPECT_TRUE(check<bool>(has_version_logging, _expected_version_logging_enabled, + "VERSION LOGGING")); + EXPECT_TRUE(check<uint32_t>(version_logging_interval, + _expected_version_logging_interval, + "VERSION LOGGING INTERVAL")); + + // watchdog + EXPECT_TRUE(its_configuration->is_watchdog_enabled()); + EXPECT_EQ(1234u, its_configuration->get_watchdog_timeout()); + EXPECT_EQ(7u, its_configuration->get_allowed_missing_pongs()); + + // file permissions + EXPECT_EQ(0222u, its_configuration->get_permissions_uds()); + + // selective broadcasts + EXPECT_TRUE(its_configuration->supports_selective_broadcasts( + boost::asio::ip::address::from_string("160.160.160.160"))); + + // tracing + std::shared_ptr<vsomeip::cfg::trace> its_trace = its_configuration->get_trace(); + EXPECT_TRUE(its_trace->is_enabled_); + EXPECT_TRUE(its_trace->is_sd_enabled_); + EXPECT_EQ(4u, its_trace->channels_.size()); + EXPECT_TRUE(its_trace->filters_.size() == 2u || its_trace->filters_.size() == 4u); + for (const auto &c : its_trace->channels_) { + EXPECT_TRUE(c->name_ == std::string("testname") || c->name_ == std::string("testname2") || + c->name_ == std::string("testname3") || c->name_ == std::string("testname4")); + if (c->name_ == std::string("testname")) { + EXPECT_EQ(std::string("testid"), c->id_); + } else if (c->name_ == std::string("testname2")) { + EXPECT_EQ(std::string("testid2"), c->id_); + } else if (c->name_ == std::string("testname3")) { + EXPECT_EQ(std::string("testid3"), c->id_); + } else if (c->name_ == std::string("testname4")) { + EXPECT_EQ(std::string("testid4"), c->id_); + } + } + for (const auto &f : its_trace->filters_) { + auto its_channel_name = f->channels_.front(); + auto its_matches = f->matches_; + EXPECT_TRUE(its_channel_name == std::string("testname") || its_channel_name == std::string("testname2") || + its_channel_name == std::string("testname3") || its_channel_name == std::string("testname4")); + if (its_channel_name == std::string("testname")) { + EXPECT_EQ(2u, its_matches.size()); + + for (const vsomeip::trace::match_t &m : its_matches) { + EXPECT_TRUE(std::get<0>(m) == vsomeip::service_t(0x1111) || + std::get<0>(m) == vsomeip::service_t(2222)); + EXPECT_TRUE(std::get<1>(m) == vsomeip::instance_t(0xffff)); + EXPECT_TRUE(std::get<2>(m) == vsomeip::method_t(0xffff)); + EXPECT_EQ(f->ftype_, vsomeip_v3::trace::filter_type_e::POSITIVE); + EXPECT_FALSE(f->is_range_); + } + } else if (its_channel_name == std::string("testname2")) { + EXPECT_EQ(2u, its_matches.size()); + + for (const vsomeip::trace::match_t &m : its_matches) { + EXPECT_TRUE(std::get<0>(m) == vsomeip::service_t(0x3333) || + std::get<0>(m) == vsomeip::service_t(4444)); + EXPECT_TRUE(std::get<1>(m) == vsomeip::instance_t(0xffff)); + EXPECT_TRUE(std::get<2>(m) == vsomeip::method_t(0xffff)); + EXPECT_NE(f->ftype_, vsomeip_v3::trace::filter_type_e::POSITIVE); + EXPECT_FALSE(f->is_range_); + } + } else if (its_channel_name == std::string("testname3")) { + EXPECT_EQ(2u, its_matches.size()); + + for (const vsomeip::trace::match_t &m : its_matches) { + EXPECT_TRUE(std::get<0>(m) == vsomeip::service_t(0x1111) || + std::get<0>(m) == vsomeip::service_t(0x3333)); + EXPECT_TRUE(std::get<1>(m) == vsomeip::instance_t(0xffff)); + EXPECT_TRUE(std::get<2>(m) == vsomeip::method_t(0xffff) || + std::get<2>(m) == vsomeip::method_t(0x8888)); + EXPECT_NE(f->ftype_, vsomeip_v3::trace::filter_type_e::POSITIVE); + EXPECT_FALSE(f->is_range_); + } + } else if (its_channel_name == std::string("testname4")) { + EXPECT_EQ(2u, its_matches.size()); + + for (const vsomeip::trace::match_t &m : its_matches) { + EXPECT_TRUE(std::get<0>(m) == vsomeip::service_t(0x1111) || + std::get<0>(m) == vsomeip::service_t(0x3333)); + EXPECT_TRUE(std::get<1>(m) == vsomeip::instance_t(0x0001)); + EXPECT_TRUE(std::get<2>(m) == vsomeip::method_t(0xffff) || + std::get<2>(m) == vsomeip::method_t(0x8888)); + EXPECT_NE(f->ftype_, vsomeip_v3::trace::filter_type_e::POSITIVE); + EXPECT_TRUE(f->is_range_); + } + } + } + + // Applications + std::size_t max_dispatchers = its_configuration->get_max_dispatchers( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t max_dispatch_time = its_configuration->get_max_dispatch_time( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t max_detached_thread_wait_time = its_configuration->get_max_detached_thread_wait_time( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t io_threads = its_configuration->get_io_thread_count( + EXPECTED_ROUTING_MANAGER_HOST); + std::size_t request_time = its_configuration->get_request_debouncing( + EXPECTED_ROUTING_MANAGER_HOST); + + EXPECT_TRUE(check<std::size_t>(max_dispatchers, + _expected_application_max_dispatcher, "MAX DISPATCHERS")); + EXPECT_TRUE(check<std::size_t>(max_dispatch_time, + _expected_application_max_dispatch_time, "MAX DISPATCH TIME")); + EXPECT_TRUE(check<std::size_t>(max_detached_thread_wait_time, + _expected_application_max_detached_thread_wait_time, "MAX DETACHED THREADS WAIT TIME")); + EXPECT_TRUE(check<std::size_t>(io_threads, _expected_application_threads, + "IO THREADS")); + EXPECT_TRUE(check<std::size_t>(request_time, + _expected_application_request_debounce_time, "REQUEST DEBOUNCE TIME")); + + EXPECT_EQ(0x9933, its_configuration->get_id("other_application")); + + std::map<vsomeip::plugin_type_e, std::set<std::string>> its_plugins = + its_configuration->get_plugins(EXPECTED_ROUTING_MANAGER_HOST); + EXPECT_EQ(1u, its_plugins.size()); + for (const auto& plugin : its_plugins) { + EXPECT_EQ(vsomeip::plugin_type_e::APPLICATION_PLUGIN, plugin.first); + for (const auto& its_library : plugin.second) + EXPECT_EQ(std::string("libtestlibraryname.so." + std::to_string(VSOMEIP_APPLICATION_PLUGIN_VERSION)), its_library); + } + EXPECT_EQ(vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, its_plugin->get_plugin_type()); + EXPECT_EQ("vsomeip-configuration-plugin", its_plugin->get_plugin_name()); + EXPECT_EQ(1u, its_plugin->get_plugin_version()); + + + // 5. Services + std::string its_unicast_address + = its_configuration->get_unicast_address(0x1234, 0x0022); + uint16_t its_reliable_port + = its_configuration->get_reliable_port(0x1234, 0x0022); + uint16_t its_unreliable_port + = its_configuration->get_unreliable_port(0x1234, 0x0022); + + EXPECT_TRUE(check<std::string>(its_unicast_address, + _expected_unicast_address_1234_0022, + "UNICAST_ADDRESS_1234_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, + _expected_reliable_port_1234_0022, + "RELIABLE_PORT_1234_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, + _expected_unreliable_port_1234_0022, + "UNRELIABLE_PORT_1234_0022")); + + its_unicast_address + = its_configuration->get_unicast_address(0x1234, 0x0023); + its_reliable_port + = its_configuration->get_reliable_port(0x1234, 0x0023); + its_unreliable_port + = its_configuration->get_unreliable_port(0x1234, 0x0023); + + EXPECT_TRUE(check<std::string>(its_unicast_address, + _expected_unicast_address_1234_0023, + "UNICAST_ADDRESS_1234_0023")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, + _expected_reliable_port_1234_0023, + "RELIABLE_PORT_1234_0023")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, + _expected_unreliable_port_1234_0023, + "UNRELIABLE_PORT_1234_0023")); + + its_unicast_address + = its_configuration->get_unicast_address(0x2277, 0x0022); + its_reliable_port + = its_configuration->get_reliable_port(0x2277, 0x0022); + its_unreliable_port + = its_configuration->get_unreliable_port(0x2277, 0x0022); + + EXPECT_TRUE(check<std::string>(its_unicast_address, + _expected_unicast_address_2277_0022, + "UNICAST_ADDRESS_2277_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, + _expected_reliable_port_2277_0022, + "RELIABLE_PORT_2277_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, + _expected_unreliable_port_2277_0022, + "UNRELIABLE_PORT_2277_0022")); + + its_unicast_address + = its_configuration->get_unicast_address(0x2266, 0x0022); + its_reliable_port + = its_configuration->get_reliable_port(0x2266, 0x0022); + its_unreliable_port + = its_configuration->get_unreliable_port(0x2266, 0x0022); + + EXPECT_TRUE(check<std::string>(its_unicast_address, + _expected_unicast_address_2266_0022, + "UNICAST_ADDRESS_2266_0022")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, + _expected_reliable_port_2266_0022, + "RELIABLE_PORT_2266_0022")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, + _expected_unreliable_port_2266_0022, + "UNRELIABLE_PORT_2266_0022")); + + its_unicast_address + = its_configuration->get_unicast_address(0x4466, 0x0321); + its_reliable_port + = its_configuration->get_reliable_port(0x4466, 0x0321); + its_unreliable_port + = its_configuration->get_unreliable_port(0x4466, 0x0321); + + EXPECT_TRUE(check<std::string>(its_unicast_address, + _expected_unicast_address_4466_0321, + "UNICAST_ADDRESS_4466_0321")); + EXPECT_TRUE(check<uint16_t>(its_reliable_port, + _expected_reliable_port_4466_0321, + "RELIABLE_PORT_4466_0321")); + EXPECT_TRUE(check<uint16_t>(its_unreliable_port, + _expected_unreliable_port_4466_0321, + "UNRELIABLE_PORT_4466_0321")); + + std::string its_multicast_address; + std::uint16_t its_multicast_port; + its_configuration->get_multicast(0x7809, 0x1, 0x1111, + its_multicast_address, its_multicast_port); + EXPECT_EQ(1234u, its_multicast_port); + EXPECT_EQ(std::string("224.212.244.225"), its_multicast_address); + EXPECT_EQ(8u, its_configuration->get_threshold(0x7809, 0x1, 0x1111)); + + EXPECT_TRUE(its_configuration->is_offered_remote(0x1234,0x0022)); + EXPECT_FALSE(its_configuration->is_offered_remote(0x3333,0x1)); + + EXPECT_TRUE(its_configuration->has_enabled_magic_cookies("10.0.2.15", 30506)); + EXPECT_FALSE(its_configuration->has_enabled_magic_cookies("10.0.2.15", 30503)); + + std::set<std::pair<vsomeip::service_t, vsomeip::instance_t>> its_remote_services = + its_configuration->get_remote_services(); + EXPECT_EQ(1u, its_remote_services.size()); + for (const auto &p : its_remote_services) { + EXPECT_EQ(0x4466, p.first); + EXPECT_EQ(0x321, p.second); + } + + EXPECT_TRUE(its_configuration->is_someip(0x3333,0x1)); + EXPECT_FALSE(its_configuration->is_someip(0x3555,0x1)); + + // Internal services + EXPECT_TRUE(its_configuration->is_local_service(0x1234, 0x0022)); + EXPECT_TRUE(its_configuration->is_local_service(0x3333,0x1)); + // defined range, service level only + EXPECT_FALSE(its_configuration->is_local_service(0xF0FF,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF100,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF101,0x23)); + EXPECT_TRUE(its_configuration->is_local_service(0xF109,0xFFFF)); + EXPECT_FALSE(its_configuration->is_local_service(0xF10a,0x1)); + // defined range, service and instance level + EXPECT_FALSE(its_configuration->is_local_service(0xF2FF,0xFFFF)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x1)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x5)); + EXPECT_TRUE(its_configuration->is_local_service(0xF300,0x10)); + EXPECT_FALSE(its_configuration->is_local_service(0xF300,0x11)); + EXPECT_FALSE(its_configuration->is_local_service(0xF301,0x11)); + + // clients + std::map<bool, std::set<uint16_t>> used_ports; + used_ports[true].insert(0x11); + used_ports[false].insert(0x10); + std::uint16_t port_to_use(0x0); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x1, vsomeip::ILLEGAL_PORT, true, used_ports, port_to_use)); + EXPECT_EQ(0x10, port_to_use); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x1, vsomeip::ILLEGAL_PORT, false, used_ports, port_to_use)); + EXPECT_EQ(0x11, port_to_use); + + used_ports[true].insert(0x10); + used_ports[false].insert(0x11); + EXPECT_FALSE(its_configuration->get_client_port(0x8888, 0x1, vsomeip::ILLEGAL_PORT, true, used_ports, port_to_use)); + EXPECT_EQ(vsomeip::ILLEGAL_PORT, port_to_use); + EXPECT_FALSE(its_configuration->get_client_port(0x8888, 0x1, vsomeip::ILLEGAL_PORT, false, used_ports, port_to_use)); + EXPECT_EQ(vsomeip::ILLEGAL_PORT, port_to_use); + + + //check for correct client port assignment if service / instance was not configured but a remote port range + used_ports.clear(); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7725, true, used_ports, port_to_use)); + EXPECT_EQ(0x771B, port_to_use); + used_ports[true].insert(0x771B); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7725, true, used_ports, port_to_use)); + EXPECT_EQ(0x771C, port_to_use); + used_ports[true].insert(0x771C); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7B0D, true, used_ports, port_to_use)); + EXPECT_EQ(0x7B03, port_to_use); + used_ports[true].insert(0x7B03); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7B0D, true, used_ports, port_to_use)); + EXPECT_EQ(0x7B04, port_to_use); + used_ports[true].insert(0x7B04); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7EF4, true, used_ports, port_to_use)); + EXPECT_EQ(0x7EEB, port_to_use); + used_ports[true].insert(0x7EEB); + EXPECT_TRUE(its_configuration->get_client_port(0x8888, 0x12, 0x7EF4, true, used_ports, port_to_use)); + EXPECT_EQ(0x7EEC, port_to_use); + used_ports[true].insert(0x7EEC); + used_ports.clear(); + + + // payload sizes + // use 17000 instead of 1500 as configured max-local-payload size will be + // increased to bigger max-reliable-payload-size + std::uint32_t max_local_message_size( + 17000u + 16u + vsomeip::protocol::SEND_COMMAND_HEADER_SIZE); + EXPECT_EQ(max_local_message_size, its_configuration->get_max_message_size_local()); + EXPECT_EQ(11u, its_configuration->get_buffer_shrink_threshold()); + EXPECT_EQ(14999u + 16u, its_configuration->get_max_message_size_reliable("10.10.10.10", 7777)); + EXPECT_EQ(17000u + 16, its_configuration->get_max_message_size_reliable("11.11.11.11", 4711)); + EXPECT_EQ(15001u + 16, its_configuration->get_max_message_size_reliable("10.10.10.11", 7778)); + + // security +#if !defined(VSOMEIP_DISABLE_SECURITY) && !defined(__QNX__) + vsomeip_sec_client_t its_x123_x456 = utility::create_uds_client(0x123, 0x456, 0); + + EXPECT_TRUE(its_configuration->check_routing_credentials(0x7788, &its_x123_x456)); + + // GID does not match + vsomeip_sec_client_t its_x123_x222 = utility::create_uds_client(0x123, 0x222, 0); + EXPECT_FALSE(its_configuration->check_routing_credentials(0x7788, &its_x123_x222)); + + // UID does not match + vsomeip_sec_client_t its_x333_x456 = utility::create_uds_client(0x333, 0x456, 0); + EXPECT_FALSE(its_configuration->check_routing_credentials(0x7788, &its_x333_x456)); + + // client is not the routing manager + vsomeip_sec_client_t its_x888_x999 = utility::create_uds_client(0x888, 0x999, 0); + EXPECT_TRUE(its_configuration->check_routing_credentials(0x7777, &its_x888_x999)); + + EXPECT_TRUE(its_configuration->is_security_enabled()); + vsomeip_sec_client_t its_1000_1000 = utility::create_uds_client(1000, 1000, 0); + vsomeip_sec_client_t its_1001_1001 = utility::create_uds_client(1001, 1001, 0); + vsomeip_sec_client_t its_2000_2000 = utility::create_uds_client(2000, 2000, 0); + vsomeip_sec_client_t its_2001_2001 = utility::create_uds_client(2001, 2001, 0); + vsomeip_sec_client_t its_4000_4000 = utility::create_uds_client(4000, 4000, 0); + vsomeip_sec_client_t its_4001_4001 = utility::create_uds_client(4001, 4001, 0); + vsomeip_sec_client_t its_5000_5000 = utility::create_uds_client(5000, 5000, 0); + vsomeip_sec_client_t its_6000_6000 = utility::create_uds_client(6000, 6000, 0); + vsomeip_sec_client_t its_7000_7000 = utility::create_uds_client(7000, 7000, 0); + vsomeip_sec_client_t its_8000_8000 = utility::create_uds_client(8000, 8000, 0); + vsomeip_sec_client_t its_9000_9000 = utility::create_uds_client(9000, 9000, 0); + + auto its_security = its_configuration->get_policy_manager(); + EXPECT_TRUE(its_security->is_offer_allowed(&its_1000_1000, 0x1234, 0x5678)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_1000_1000, 0x1235, 0x5678)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_1000_1000, 0x1236, 0x5678)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_1000_1000, 0x1236, 0x5676)); + + EXPECT_FALSE(its_security->is_offer_allowed(&its_1000_1000, 0x1236, 0x5679)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_1000_1000, 0x1234, 0x5679)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_1000_1000, 0x1233, 0x5679)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_1001_1001, 0x1233, 0x5679)); + // explicitly denied offers + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1234, 0x5678)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1235, 0x5678)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_4000_4000, 0x1234, 0x5679)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_4000_4000, 0x1300, 0x1)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_4000_4000, 0x1300, 0x2)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1236, 0x5678)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1236, 0x5675)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1236, 0x5676)); + EXPECT_FALSE(its_security->is_offer_allowed(&its_4000_4000, 0x1236, 0x5677)); + EXPECT_TRUE(its_security->is_offer_allowed(&its_4000_4000, 0x1236, 0x5679)); + + // explicitly allowed requests of methods / events + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5678, 0x0001)); + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5678, 0x8002)); + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5688, 0x8002)); + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5699, 0x8006)); + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5699, 0x8001)); + + EXPECT_FALSE(its_security->is_client_allowed(&its_2001_2001, 0x1234, 0x5678, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2001_2001, 0x1234, 0x5678, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5677, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5700, 0x0001)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5699, 0x8007)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1234, 0x5700, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1230, 0x5678, 0x0001)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1230, 0x5678, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5678, 0x0002)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5678, 0xFFFF)); + EXPECT_TRUE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5679, 0x0003)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5679, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5699, 0x9001)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4000_4000, 0x1234, 0x5699, 0x9006)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4001_4001, 0x1234, 0x5678, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_4001_4001, 0x1234, 0x5678, 0xFFFF)); + + // check that any method ID is allowed + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1237, 0x5678, 0x0001)); + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1237, 0x5678, 0xFFFF)); + + // check that any instance ID is allowed but only one method ID + EXPECT_TRUE(its_security->is_client_allowed(&its_2000_2000, 0x1238, 0x0004, 0x0001)); + EXPECT_FALSE(its_security->is_client_allowed(&its_2000_2000, 0x1238, 0x0004, 0x0002)); + + // DENY NOTHING policy + // check that ANY_METHOD is allowed in a "deny nothing" policy + EXPECT_TRUE(its_security->is_client_allowed(&its_5000_5000, 0x1234, 0x5678, 0xFFFF)); + // check that specific method ID is allowed in a "deny nothing" policy + EXPECT_TRUE(its_security->is_client_allowed(&its_5000_5000, 0x1234, 0x5678, 0x0001)); + + // ALLOW NOTHING policy + // check that ANY_METHOD is denied in a "allow nothing" policy + EXPECT_FALSE(its_security->is_client_allowed(&its_6000_6000, 0x1234, 0x5678, 0xFFFF)); + // check that specific method ID is denied in a "allow nothing" policy + EXPECT_FALSE(its_security->is_client_allowed(&its_6000_6000, 0x1234, 0x5678, 0x0001)); + + // DENY only one service instance and ANY_METHOD (0x01 - 0xFFFF) policy + EXPECT_FALSE(its_security->is_client_allowed(&its_7000_7000, 0x1234, 0x5678, 0xFFFF)); + EXPECT_FALSE(its_security->is_client_allowed(&its_7000_7000, 0x1234, 0x5678, 0x0001)); + + // allow only one service instance and ANY_METHOD policy + EXPECT_TRUE(its_security->is_client_allowed(&its_8000_8000, 0x1234, 0x5678, 0xFFFF)); + EXPECT_TRUE(its_security->is_client_allowed(&its_8000_8000, 0x1234, 0x5678, 0x0001)); + + // check request service + EXPECT_TRUE(its_security->is_client_allowed(&its_5000_5000, 0x1234, 0x5678, 0x00, true)); + EXPECT_FALSE(its_security->is_client_allowed(&its_6000_6000, 0x1234, 0x5678, 0x00, true)); + EXPECT_FALSE(its_security->is_client_allowed(&its_7000_7000, 0x1234, 0x5678, 0x00, true)); + EXPECT_TRUE(its_security->is_client_allowed(&its_7000_7000, 0x2222, 0x5678, 0x00, true)); + EXPECT_TRUE(its_security->is_client_allowed(&its_8000_8000, 0x1234, 0x5678, 0x00, true)); + + EXPECT_TRUE(its_security->check_credentials(0x1277, &its_1000_1000)); + EXPECT_FALSE(its_security->check_credentials(0x1277, &its_1001_1001)); + EXPECT_TRUE(its_security->check_credentials(0x1278, &its_1000_1000)); + EXPECT_TRUE(its_security->check_credentials(0x1278, &its_9000_9000)); + + // Security update / removal whitelist + EXPECT_TRUE(its_security->is_policy_removal_allowed(1000)); + EXPECT_TRUE(its_security->is_policy_removal_allowed(1001)); + EXPECT_TRUE(its_security->is_policy_removal_allowed(1008)); + EXPECT_TRUE(its_security->is_policy_removal_allowed(2000)); + EXPECT_TRUE(its_security->is_policy_removal_allowed(3000)); + + EXPECT_FALSE(its_security->is_policy_removal_allowed(2001)); + EXPECT_FALSE(its_security->is_policy_removal_allowed(3001)); + + // create a valid policy object that is on whitelist and test is_policy_update_allowed method + std::shared_ptr<vsomeip::policy> _policy(std::make_shared<vsomeip::policy>()); + uint32_t its_uid = 1000; + uint32_t its_gid = 1000; + + // policy elements + boost::icl::discrete_interval<uid_t> its_uids(its_uid, its_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(its_gid, its_gid)); + + _policy->credentials_ += std::make_pair(its_uids, its_gids); + _policy->allow_who_ = true; + _policy->allow_what_ = true; + + vsomeip::service_t its_service(0x1234); + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, + boost::icl::interval_set<vsomeip::method_t> > its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + _policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + its_service, its_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + EXPECT_TRUE(its_security->is_policy_update_allowed(1000, _policy)); + + // test valid policy that holds a single service id which is whitelisted + vsomeip::service_t its_second_service(0x7800); + _policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + its_second_service, its_second_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + EXPECT_TRUE(its_security->is_policy_update_allowed(1000, _policy)); + + // test invalid UID which is not whitelisted + EXPECT_FALSE(its_security->is_policy_update_allowed(2002, _policy)); + + // test invalid policy that additionally holds a service id which is not whitelisted + vsomeip::service_t its_third_service(0x8888); + _policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + its_third_service, its_third_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + EXPECT_FALSE(its_security->is_policy_update_allowed(1000, _policy)); +#endif // !VSOMEIP_DISABLE_SECURITY + + // TCP connection setting: + // max TCP connect time / max allowed number of aborted TCP endpoint restarts until forced restart + EXPECT_EQ(its_configuration->get_max_tcp_connect_time(), 10000u); + EXPECT_EQ(its_configuration->get_max_tcp_restart_aborts(), 15u); + + // 6. Service discovery + bool enabled = its_configuration->is_sd_enabled(); + std::string protocol = its_configuration->get_sd_protocol(); + uint16_t port = its_configuration->get_sd_port(); + std::string multicast = its_configuration->get_sd_multicast(); + + uint32_t initial_delay_min = its_configuration->get_sd_initial_delay_min(); + uint32_t initial_delay_max = its_configuration->get_sd_initial_delay_max(); + int32_t repetitions_base_delay = its_configuration->get_sd_repetitions_base_delay(); + uint8_t repetitions_max = its_configuration->get_sd_repetitions_max(); + vsomeip::ttl_t ttl = its_configuration->get_sd_ttl(); + int32_t cyclic_offer_delay = its_configuration->get_sd_cyclic_offer_delay(); + int32_t request_response_delay = its_configuration->get_sd_request_response_delay(); + + EXPECT_TRUE(check<bool>(enabled, _expected_enabled, "SD ENABLED")); + EXPECT_TRUE(check<std::string>(protocol, _expected_protocol, "SD PROTOCOL")); + EXPECT_TRUE(check<std::string>(multicast, _expected_multicast, "SD MULTICAST")); + EXPECT_TRUE(check<uint16_t>(port, _expected_port, "SD PORT")); + + EXPECT_TRUE(check<uint32_t>(initial_delay_min, _expected_initial_delay_min, "SD INITIAL DELAY MIN")); + EXPECT_TRUE(check<uint32_t>(initial_delay_max, _expected_initial_delay_max, "SD INITIAL DELAY MAX")); + EXPECT_TRUE(check<int32_t>(repetitions_base_delay, _expected_repetitions_base_delay, "SD REPETITION BASE DELAY")); + EXPECT_TRUE(check<uint8_t>(repetitions_max,_expected_repetitions_max, "SD REPETITION MAX")); + EXPECT_TRUE(check<vsomeip::ttl_t>(ttl, _expected_ttl, "SD TTL")); + EXPECT_TRUE(check<int32_t>(cyclic_offer_delay, static_cast<int32_t>(_expected_cyclic_offer_delay), "SD CYCLIC OFFER DELAY")); + EXPECT_TRUE(check<int32_t>(request_response_delay, static_cast<int32_t>(_expected_request_response_delay), "SD RESPONSE REQUEST DELAY")); + EXPECT_EQ(1000u, its_configuration->get_sd_offer_debounce_time()); + + ASSERT_TRUE(vsomeip::plugin_manager::get()->unload_plugin(vsomeip::plugin_type_e::CONFIGURATION_PLUGIN)); +} + +TEST(configuration_test, check_config_file) { + // Check current configuration file format + check_file(CONFIGURATION_FILE, + EXPECTED_UNICAST_ADDRESS, + EXPECTED_HAS_CONSOLE, + EXPECTED_HAS_FILE, + EXPECTED_HAS_DLT, + EXPECTED_VERSION_LOGGING_ENABLED, + EXPECTED_VERSION_LOGGING_INTERVAL, + EXPECTED_APPLICATION_MAX_DISPATCHERS, + EXPECTED_APPLICATION_MAX_DISPATCH_TIME, + EXPECTED_APPLICATION_MAX_DETACHED_THREAD_WAIT_TIME, + EXPECTED_APPLICATION_THREADS, + EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME, + EXPECTED_LOGFILE, + EXPECTED_LOGLEVEL, + EXPECTED_UNICAST_ADDRESS_1234_0022, + EXPECTED_RELIABLE_PORT_1234_0022, + EXPECTED_UNRELIABLE_PORT_1234_0022, + EXPECTED_UNICAST_ADDRESS_1234_0023, + EXPECTED_RELIABLE_PORT_1234_0023, + EXPECTED_UNRELIABLE_PORT_1234_0023, + EXPECTED_UNICAST_ADDRESS_2277_0022, + EXPECTED_RELIABLE_PORT_2277_0022, + EXPECTED_UNRELIABLE_PORT_2277_0022, + EXPECTED_UNICAST_ADDRESS_2266_0022, + EXPECTED_RELIABLE_PORT_2266_0022, + EXPECTED_UNRELIABLE_PORT_2266_0022, + EXPECTED_UNICAST_ADDRESS_4466_0321, + EXPECTED_RELIABLE_PORT_4466_0321, + EXPECTED_UNRELIABLE_PORT_4466_0321, + EXPECTED_SD_ENABLED, + EXPECTED_SD_PROTOCOL, + EXPECTED_SD_MULTICAST, + EXPECTED_SD_PORT, + EXPECTED_INITIAL_DELAY_MIN, + EXPECTED_INITIAL_DELAY_MAX, + EXPECTED_REPETITIONS_BASE_DELAY, + EXPECTED_REPETITIONS_MAX, + EXPECTED_TTL, + EXPECTED_CYCLIC_OFFER_DELAY, + EXPECTED_REQUEST_RESPONSE_DELAY); +} + +TEST(configuration_test, check_deprecated_config_file) { + // Check deprecated configuration file format + check_file(DEPRECATED_CONFIGURATION_FILE, + EXPECTED_UNICAST_ADDRESS, + EXPECTED_HAS_CONSOLE, + EXPECTED_HAS_FILE, + EXPECTED_HAS_DLT, + EXPECTED_VERSION_LOGGING_ENABLED, + EXPECTED_VERSION_LOGGING_INTERVAL, + EXPECTED_APPLICATION_MAX_DISPATCHERS, + EXPECTED_APPLICATION_MAX_DISPATCH_TIME, + EXPECTED_APPLICATION_MAX_DETACHED_THREAD_WAIT_TIME, + EXPECTED_APPLICATION_THREADS, + EXPECTED_APPLICATION_REQUEST_DEBOUNCE_TIME, + EXPECTED_LOGFILE, + EXPECTED_LOGLEVEL, + EXPECTED_UNICAST_ADDRESS_1234_0022, + EXPECTED_RELIABLE_PORT_1234_0022, + EXPECTED_UNRELIABLE_PORT_1234_0022, + EXPECTED_UNICAST_ADDRESS_1234_0023, + EXPECTED_RELIABLE_PORT_1234_0023, + EXPECTED_UNRELIABLE_PORT_1234_0023, + EXPECTED_UNICAST_ADDRESS_2277_0022, + EXPECTED_RELIABLE_PORT_2277_0022, + EXPECTED_UNRELIABLE_PORT_2277_0022, + EXPECTED_UNICAST_ADDRESS_2266_0022, + EXPECTED_RELIABLE_PORT_2266_0022, + EXPECTED_UNRELIABLE_PORT_2266_0022, + EXPECTED_UNICAST_ADDRESS_4466_0321, + EXPECTED_RELIABLE_PORT_4466_0321, + EXPECTED_UNRELIABLE_PORT_4466_0321, + EXPECTED_SD_ENABLED, + EXPECTED_SD_PROTOCOL, + EXPECTED_SD_MULTICAST, + EXPECTED_SD_PORT, + EXPECTED_DEPRECATED_INITIAL_DELAY_MIN, + EXPECTED_DEPRECATED_INITIAL_DELAY_MAX, + EXPECTED_DEPRECATED_REPETITIONS_BASE_DELAY, + EXPECTED_DEPRECATED_REPETITIONS_MAX, + EXPECTED_DEPRECATED_TTL, + EXPECTED_CYCLIC_OFFER_DELAY, + EXPECTED_DEPRECATED_REQUEST_RESPONSE_DELAY); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/CMakeLists.txt new file mode 100644 index 00000000000..843edf129fb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +# Configure necessary files into the build folder. +set(configuration_files + cpu_load_test_client_master.json + cpu_load_test_client_slave.json + cpu_load_test_master_starter.sh + cpu_load_test_service_master.json + cpu_load_test_service_slave.json + cpu_load_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(cpu_load_test_service + cpu_load_test_service.cpp + cpu_load_measurer.cpp +) + +# Add test executable. +add_executable(cpu_load_test_client + cpu_load_test_client.cpp + cpu_load_measurer.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + cpu_load_test_client + cpu_load_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME cpu_load_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/cpu_load_test_master_starter.sh + TIMEOUT 3000 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in new file mode 100644 index 00000000000..4eda44a59ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in @@ -0,0 +1,38 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "cpu_load_test_client", + "id" : "0x2222" + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "cpu_load_test_client", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in new file mode 100644 index 00000000000..c4ac4c521ea --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in @@ -0,0 +1,38 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "cpu_load_test_client", + "id" : "0x2222" + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "cpu_load_test_client", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_master_starter.sh.in new file mode 100755 index 00000000000..f1950bf2be8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_master_starter.sh.in @@ -0,0 +1,75 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=cpu_load_test_client_master.json +./cpu_load_test_client --protocol UDP --calls 1000 & +TEST_CLIENT_PID=$! +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting cpu load test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP 'bash -ci "set -m; cd \$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/cpu_load_tests; ./cpu_load_test_slave_starter.sh"' & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./cpu_load_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** cpu_load_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** cpu_load_test_client_master.json, +** cpu_load_test_service_master.json, +** cpu_load_test_client_client.json and +** cpu_load_test_service_client.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $TEST_CLIENT_PID || FAIL=$(($FAIL+1)) + + +sleep 4 +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Now switching roles and running service on this host (master) +******************************************************************************* +******************************************************************************* +End-of-message + +export VSOMEIP_CONFIGURATION=cpu_load_test_service_master.json +./cpu_load_test_service & +sleep 1 + +# now we can wait to all jobs to finish +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in new file mode 100644 index 00000000000..89d41c23cac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in @@ -0,0 +1,51 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "cpu_load_test_service", + "id" : "0x1111" + } + ], + + "services" : + [ + { + "service" : "0x1111", + "instance" : "0x1", + "unreliable" : "30510", + "reliable" : + { + "port" : "30510", + "enable-magic-cookies" : "false" + } + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "cpu_load_test_service", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in new file mode 100644 index 00000000000..db28f210b3a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in @@ -0,0 +1,51 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "cpu_load_test_service", + "id" : "0x1111" + } + ], + + "services" : + [ + { + "service" : "0x1111", + "instance" : "0x1", + "unreliable" : "30510", + "reliable" : + { + "port" : "30510", + "enable-magic-cookies" : "false" + } + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "cpu_load_test_service", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_slave_starter.sh.in new file mode 100755 index 00000000000..83ef19dc5df --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/conf/cpu_load_test_slave_starter.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=cpu_load_test_service_slave.json +./cpu_load_test_service & + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Now switching roles and running client on this host (slave) +******************************************************************************* +******************************************************************************* +End-of-message + +sleep 4 +export VSOMEIP_CONFIGURATION=cpu_load_test_client_slave.json +./cpu_load_test_client --protocol UDP --calls 1000 & + +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp new file mode 100644 index 00000000000..d4360b356dd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "cpu_load_measurer.hpp" + +#include <fstream> +#include <string> +#include <iostream> +#include <sstream> +#include <vector> +#include <stdexcept> +#include <cstdio> + +#include <sys/types.h> +#include <unistd.h> + +cpu_load_measurer::~cpu_load_measurer() { +} + +cpu_load_measurer::cpu_load_measurer(std::uint32_t _pid) : + pid_(_pid), + jiffies_complete_start_(0), + jiffies_idle_start_(0), + jiffies_complete_stop_(0), + jiffies_idle_stop_(0), + clock_ticks_(0), + jiffies_passed_pid_start_(0), + jiffies_passed_pid_stop_(0), + cpu_load_pid_(0.0), + cpu_load_overall_(0.0), + cpu_load_pid_wo_idle_(0.0) { +} + +void cpu_load_measurer::start() { + // reset everything + jiffies_complete_start_ = 0; + jiffies_idle_start_ = 0; + jiffies_complete_stop_ = 0; + jiffies_idle_stop_ = 0; + clock_ticks_ = 0; + jiffies_passed_pid_start_ = 0; + jiffies_passed_pid_stop_ = 0; + cpu_load_pid_= 0.0; + cpu_load_overall_ = 0.0; + cpu_load_pid_wo_idle_ = 0.0; + //start + jiffies_complete_start_ = read_proc_stat(&jiffies_idle_start_); + jiffies_passed_pid_start_ = read_proc_pid_stat(); +} + +void cpu_load_measurer::stop() { + jiffies_complete_stop_ = read_proc_stat(&jiffies_idle_stop_); + jiffies_passed_pid_stop_ = read_proc_pid_stat(); + if(jiffies_complete_stop_ < jiffies_complete_start_ || jiffies_passed_pid_stop_ < jiffies_passed_pid_start_) { + std::cerr << "Overflow of values in procfs occured, can't calculate load" << std::endl; + exit(0); + } + cpu_load_pid_ = 100.0 + * static_cast<double>(jiffies_passed_pid_stop_ + - jiffies_passed_pid_start_) + / static_cast<double>(jiffies_complete_stop_ + - jiffies_complete_start_); + cpu_load_overall_ = 100.0 + * static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_) + - (jiffies_complete_start_ - jiffies_idle_start_)) + / static_cast<double>(jiffies_complete_stop_ + - jiffies_complete_start_); + cpu_load_pid_wo_idle_ = 100.0 + * static_cast<double>(jiffies_passed_pid_stop_ + - jiffies_passed_pid_start_) + / static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_) + - (jiffies_complete_start_ - jiffies_idle_start_)); + +} + +void cpu_load_measurer::print_cpu_load() const { + std::cout << "Used Jiffies complete: " + << jiffies_complete_stop_ - jiffies_complete_start_ << " (worked: " + << (jiffies_complete_stop_ - jiffies_idle_stop_) + - (jiffies_complete_start_ - jiffies_idle_start_) + << " idled: " << jiffies_idle_stop_ - jiffies_idle_start_ + << ")" << std::endl; + std::cout << "Used Jiffies of pid " << pid_ << ": " << jiffies_passed_pid_stop_ - jiffies_passed_pid_start_ << std::endl; + std::cout << "Cpu load pid " << pid_ << " [%]: " << cpu_load_pid_ << std::endl; + std::cout << "Overall cpu load[%]: " << cpu_load_overall_ << std::endl; + std::cout << "Load caused by pid " << pid_ << " of overall cpu load [%]:" << cpu_load_pid_wo_idle_ << std::endl; +} + +double cpu_load_measurer::get_cpu_load() const { + return cpu_load_pid_; +} + +std::uint64_t cpu_load_measurer::read_proc_pid_stat() { + std::string path("/proc/" + std::to_string(pid_) + "/stat"); + FILE* f = std::fopen(path.c_str(), "r"); + if(!f) { + std::perror(std::string("Failed to open " + path).c_str()); + exit(1); + } + // see Table 1-4 Contents of the stat files (as of 2.6.30-rc7) + // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98 + // and man proc (for conversion specifier) + std::uint64_t utime(0); + std::uint64_t stime(0); + std::int64_t cutime(0); + std::int64_t cstime(0); + if (std::fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " + "%lu %lu %ld %ld", // utime, stime, cutime, cstime + &utime, &stime, &cutime, &cstime) == EOF) { + std::cerr << "Failed to read " + path << std::endl; + exit(1); + } + std::fclose(f); + return utime + stime + static_cast<std::uint64_t>(cutime) + + static_cast<std::uint64_t>(cstime); +} + +std::uint64_t cpu_load_measurer::read_proc_stat(std::uint64_t* _idle) { + FILE* f = std::fopen("/proc/stat", "r"); + if(!f) { + std::perror("Failed to open /proc/stat"); + exit(1); + } + + // see 1.8 Miscellaneous kernel statistics in /proc/stat + // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98 + std::uint64_t user(0); + std::uint64_t nice(0); + std::uint64_t system(0); + std::uint64_t idle(0); + std::uint64_t iowait(0); + std::uint64_t irq(0); + std::uint64_t softirq(0); + std::uint64_t steal(0); + std::uint64_t guest(0); + std::uint64_t guest_nice(0); + if (std::fscanf(f, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &user, + &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, + &guest_nice) == EOF) { + std::cerr << "Failed to read /proc/stat" << std::endl; + exit(1); + } + std::fclose(f); + *_idle = idle; + return user + nice + system + idle + iowait + irq + softirq + steal + guest + + guest_nice; +} + +bool cpu_load_measurer::read_clock_ticks() { + long val(::sysconf(_SC_CLK_TCK)); + if(val < 0 && errno == EINVAL) { + std::perror(__func__); + return false; + } + clock_ticks_ = static_cast<std::uint64_t>(val); + return true; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp new file mode 100644 index 00000000000..dfdcf80b220 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <cstdint> + +class cpu_load_measurer { +public: + cpu_load_measurer(std::uint32_t _pid); + virtual ~cpu_load_measurer(); + void start(); + void stop(); + void print_cpu_load() const; + double get_cpu_load() const; + +private: + std::uint64_t read_proc_stat(std::uint64_t* _idle); + std::uint64_t read_proc_pid_stat(); + bool read_clock_ticks(); +private: + std::uint32_t pid_; + std::uint64_t jiffies_complete_start_; + std::uint64_t jiffies_idle_start_; + std::uint64_t jiffies_complete_stop_; + std::uint64_t jiffies_idle_stop_; + std::uint64_t clock_ticks_; + std::uint64_t jiffies_passed_pid_start_; + std::uint64_t jiffies_passed_pid_stop_; + double cpu_load_pid_; + double cpu_load_overall_; + double cpu_load_pid_wo_idle_; +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp new file mode 100644 index 00000000000..0730d37e1f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp @@ -0,0 +1,390 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> +#include <iomanip> +#include <numeric> +#include <cmath> // for isfinite +#include <atomic> + +#include "cpu_load_test_globals.hpp" +#include <vsomeip/internal/logger.hpp> +#include "cpu_load_measurer.hpp" + +// for getpid +#include <sys/types.h> +#include <unistd.h> + + +enum protocol_e { + PR_UNKNOWN, + PR_TCP, + PR_UDP +}; + +class cpu_load_test_client +{ +public: + cpu_load_test_client(protocol_e _protocol, std::uint32_t _number_of_calls, + std::uint32_t _payload_size, bool _call_service_sync, + bool _shutdown_service) : + protocol_(_protocol), + app_(vsomeip::runtime::get()->create_application("cpu_load_test_client")), + request_(vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP)), + call_service_sync_(_call_service_sync), + shutdown_service_at_end_(_shutdown_service), + sliding_window_size_(_number_of_calls), + wait_for_availability_(true), + is_available_(false), + number_of_calls_(_number_of_calls), + number_of_calls_current_(0), + number_of_sent_messages_(0), + number_of_sent_messages_total_(0), + number_of_acknowledged_messages_(0), + payload_size_(_payload_size), + wait_for_all_msg_acknowledged_(true), + initialized_(false), + sender_(std::bind(&cpu_load_test_client::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + initialized_ = true; + app_->register_state_handler( + std::bind(&cpu_load_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&cpu_load_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(cpu_load_test::service_id, + cpu_load_test::instance_id, + std::bind(&cpu_load_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + VSOMEIP_INFO << "Starting..."; + app_->start(); + } + + ~cpu_load_test_client() { + { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_availability_ = false; + condition_.notify_one(); + } + { + std::lock_guard<std::mutex> its_lock(all_msg_acknowledged_mutex_); + wait_for_all_msg_acknowledged_ = false; + all_msg_acknowledged_cv_.notify_one(); + } + sender_.join(); + } + +private: + void stop() { + VSOMEIP_INFO << "Stopping..."; + // shutdown the service + if(shutdown_service_at_end_) + { + shutdown_service(); + } + app_->clear_all_handler(); + } + + void on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + app_->request_service(cpu_load_test::service_id, + cpu_load_test::instance_id); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') + << std::hex << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if (cpu_load_test::service_id == _service + && cpu_load_test::instance_id == _instance) { + if (is_available_ && !_is_available) { + is_available_ = false; + } else if (_is_available && !is_available_) { + is_available_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_availability_ = false; + condition_.notify_one(); + } + } + } + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + + number_of_acknowledged_messages_++; + ASSERT_EQ(_response->get_service(), cpu_load_test::service_id); + ASSERT_EQ(_response->get_method(), cpu_load_test::method_id); + if(call_service_sync_) + { + // We notify the sender thread every time a message was acknowledged + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + wait_for_all_msg_acknowledged_ = false; + all_msg_acknowledged_cv_.notify_one(); + } + else + { + // We notify the sender thread only if all sent messages have been acknowledged + if(number_of_acknowledged_messages_ == number_of_calls_current_) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + number_of_acknowledged_messages_ = 0; + wait_for_all_msg_acknowledged_ = false; + all_msg_acknowledged_cv_.notify_one(); + } + else if(number_of_acknowledged_messages_ % sliding_window_size_ == 0) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + wait_for_all_msg_acknowledged_ = false; + all_msg_acknowledged_cv_.notify_one(); + } + } + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_for_availability_) { + condition_.wait(its_lock); + } + + request_->set_service(cpu_load_test::service_id); + request_->set_instance(cpu_load_test::instance_id); + request_->set_method(cpu_load_test::method_id); + std::shared_ptr<vsomeip::payload> payload = vsomeip::runtime::get()->create_payload(); + std::vector<vsomeip::byte_t> payload_data; + payload_data.assign(payload_size_, cpu_load_test::load_test_data); + payload->set_data(payload_data); + request_->set_payload(payload); + + // lock the mutex + for(std::uint32_t i=0; i <= number_of_calls_; i++) { + number_of_calls_current_ = i; + sliding_window_size_ = i; + std::unique_lock<std::mutex> lk(all_msg_acknowledged_mutex_); + call_service_sync_ ? send_messages_sync(lk, i) : send_messages_async(lk, i); + } + const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size())); + VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_ + << " messages in total (excluding control messages). This caused: " + << std::fixed << std::setprecision(2) + << average_load << "% load in average (average of " + << results_.size() << " measurements)."; + + std::vector<double> results_no_zero; + for(const auto &v : results_) { + if(v > 0.0) { + results_no_zero.push_back(v); + } + } + const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size())); + VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_ + << " messages in total (excluding control messages). This caused: " + << std::fixed << std::setprecision(2) + << average_load_no_zero << "% load in average, if measured " + << "cpu load was greater zero (average of " + << results_no_zero.size() << " measurements)."; + + wait_for_availability_ = true; + + stop(); + if (initialized_) { + app_->stop(); + } + } + + + void send_messages_sync(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) { + cpu_load_measurer c(static_cast<std::uint32_t>(::getpid())); + send_service_start_measuring(true); + c.start(); + for (number_of_sent_messages_ = 0; + number_of_sent_messages_ < _messages_to_send; + number_of_sent_messages_++, number_of_sent_messages_total_++) + { + app_->send(request_); + // wait until the send messages has been acknowledged + while(wait_for_all_msg_acknowledged_) { + all_msg_acknowledged_cv_.wait(lk); + } + wait_for_all_msg_acknowledged_ = true; + } + c.stop(); + send_service_start_measuring(false); + VSOMEIP_DEBUG << "Synchronously sent " << std::setw(4) << std::setfill('0') + << number_of_sent_messages_ << " messages. CPU load [%]: " + << std::fixed << std::setprecision(2) + << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0); + results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0); + + } + + void send_messages_async(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) { + cpu_load_measurer c(static_cast<std::uint32_t>(::getpid())); + send_service_start_measuring(true); + c.start(); + for (number_of_sent_messages_ = 0; + number_of_sent_messages_ < _messages_to_send; + number_of_sent_messages_++, number_of_sent_messages_total_++) + { + app_->send(request_); + if((number_of_sent_messages_+1) % sliding_window_size_ == 0) + { + // wait until all send messages have been acknowledged + while(wait_for_all_msg_acknowledged_) { + all_msg_acknowledged_cv_.wait(lk); + } + wait_for_all_msg_acknowledged_ = true; + } + } + c.stop(); + send_service_start_measuring(false); + VSOMEIP_DEBUG << "Asynchronously sent " << std::setw(4) << std::setfill('0') + << number_of_sent_messages_ << " messages. CPU load [%]: " + << std::fixed << std::setprecision(2) + << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0); + results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0); + } + + void send_service_start_measuring(bool _start_measuring) { + std::shared_ptr<vsomeip::message> m = vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP); + m->set_service(cpu_load_test::service_id); + m->set_instance(cpu_load_test::instance_id); + _start_measuring ? m->set_method(cpu_load_test::method_id_cpu_measure_start) : m->set_method(cpu_load_test::method_id_cpu_measure_stop); + app_->send(m); + } + + void shutdown_service() { + request_->set_service(cpu_load_test::service_id); + request_->set_instance(cpu_load_test::instance_id); + request_->set_method(cpu_load_test::method_id_shutdown); + app_->send(request_); + } + +private: + protocol_e protocol_; + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + bool call_service_sync_; + bool shutdown_service_at_end_; + std::uint32_t sliding_window_size_; + std::mutex mutex_; + std::condition_variable condition_; + bool wait_for_availability_; + bool is_available_; + const std::uint32_t number_of_calls_; + std::uint32_t number_of_calls_current_; + std::uint32_t number_of_sent_messages_; + std::uint32_t number_of_sent_messages_total_; + std::uint32_t number_of_acknowledged_messages_; + + std::uint32_t payload_size_; + + bool wait_for_all_msg_acknowledged_; + std::mutex all_msg_acknowledged_mutex_; + std::condition_variable all_msg_acknowledged_cv_; + std::vector<double> results_; + std::atomic<bool> initialized_; + std::thread sender_; +}; + + +// this variables are changed via cmdline parameters +static protocol_e protocol(protocol_e::PR_UNKNOWN); +static std::uint32_t number_of_calls(0); +static std::uint32_t payload_size(40); +static bool call_service_sync(true); +static bool shutdown_service(true); + + +TEST(someip_load_test, DISABLED_send_messages_and_measure_cpu_load) +{ + cpu_load_test_client test_client_(protocol, number_of_calls, payload_size, call_service_sync, shutdown_service); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + int i = 0; + while (i < argc) { + if(std::string("--protocol") == std::string(argv[i]) + || std::string("-p") == std::string(argv[i])) { + if(std::string("udp") == std::string(argv[i+1]) || + std::string("UDP") == std::string(argv[i+1])) { + protocol = protocol_e::PR_UDP; + i++; + } else if(std::string("tcp") == std::string(argv[i+1]) || + std::string("TCP") == std::string(argv[i+1])) { + protocol = protocol_e::PR_TCP; + i++; + } + } else if(std::string("--calls") == std::string(argv[i]) + || std::string("-c") == std::string(argv[i])) { + try { + number_of_calls = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10)); + } catch (const std::exception &e) { + std::cerr << "Please specify a valid value for number of calls" << std::endl; + return(EXIT_FAILURE); + } + i++; + } else if(std::string("--mode") == std::string(argv[i]) + || std::string("-m") == std::string(argv[i])) { + if(std::string("sync") == std::string(argv[i+1]) || + std::string("SYNC") == std::string(argv[i+1])) { + call_service_sync = true; + i++; + } else if(std::string("async") == std::string(argv[i+1]) || + std::string("ASYNC") == std::string(argv[i+1])) { + call_service_sync = false; + i++; + } + } else if(std::string("--payload-size") == std::string(argv[i]) + || std::string("-pl") == std::string(argv[i])) { + try { + payload_size = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10)); + } catch (const std::exception &e) { + std::cerr << "Please specify a valid values for payload size" << std::endl; + return(EXIT_FAILURE); + } + i++; + } else if(std::string("--help") == std::string(argv[i]) + || std::string("-h") == std::string(argv[i])) { + std::cout << "Available options:" << std::endl; + std::cout << "--protocol|-p: valid values TCP or UDP" << std::endl; + std::cout << "--calls|-c: number of message calls to do" << std::endl; + std::cout << "--mode|-m: mode sync or async" << std::endl; + std::cout << "--payload-size|-pl: payload size in Bytes default: 40" << std::endl; + } + i++; + } + + if(protocol == protocol_e::PR_UNKNOWN) { + std::cerr << "Please specify valid protocol mode, see --help" << std::endl; + return(EXIT_FAILURE); + } + if(!number_of_calls) { + std::cerr << "Please specify valid number of calls, see --help" << std::endl; + return(EXIT_FAILURE); + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp new file mode 100644 index 00000000000..e6897e395d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp @@ -0,0 +1,18 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +namespace cpu_load_test { + +static constexpr vsomeip::service_t service_id(0x1111); +static constexpr vsomeip::instance_t instance_id(0x1); +static constexpr vsomeip::method_t method_id(0x1111); +static constexpr vsomeip::byte_t load_test_data(0xDD); +static constexpr vsomeip::length_t default_payload_length(40); +static constexpr vsomeip::method_t method_id_shutdown(0x7777); +static constexpr vsomeip::method_t method_id_cpu_measure_start(0x8888); +static constexpr vsomeip::method_t method_id_cpu_measure_stop(0x9999); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp new file mode 100644 index 00000000000..8bf00cf2f59 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp @@ -0,0 +1,210 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <cmath> // for isfinite +#include <condition_variable> +#include <functional> +#include <iomanip> +#include <mutex> +#include <numeric> +#include <thread> + +#include "cpu_load_test_globals.hpp" +#include <vsomeip/internal/logger.hpp> +#include "cpu_load_measurer.hpp" + +// for getpid +#include <sys/types.h> +#include <unistd.h> + +class cpu_load_test_service +{ +public: + cpu_load_test_service() : + app_(vsomeip::runtime::get()->create_application("cpu_load_test_service")), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + number_of_received_messages_total_(0), + load_measurer_(static_cast<std::uint32_t>(::getpid())), + offer_thread_(std::bind(&cpu_load_test_service::run, this)) + { + } + + ~cpu_load_test_service() { + { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + offer_thread_.join(); + } + + bool init() + { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(cpu_load_test::service_id, + cpu_load_test::instance_id, cpu_load_test::method_id, + std::bind(&cpu_load_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(cpu_load_test::service_id, + cpu_load_test::instance_id, cpu_load_test::method_id_shutdown, + std::bind(&cpu_load_test_service::on_message_shutdown, this, + std::placeholders::_1)); + app_->register_message_handler(cpu_load_test::service_id, + cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_start, + std::bind(&cpu_load_test_service::on_message_start_measuring, this, + std::placeholders::_1)); + app_->register_message_handler(cpu_load_test::service_id, + cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_stop, + std::bind(&cpu_load_test_service::on_message_stop_measuring, this, + std::placeholders::_1)); + app_->register_state_handler( + std::bind(&cpu_load_test_service::on_state, this, + std::placeholders::_1)); + return true; + } + + void start() + { + VSOMEIP_INFO << "Starting..."; + app_->start(); + } + + void stop() + { + VSOMEIP_INFO << "Stopping..."; + app_->stop_offer_service(cpu_load_test::service_id, cpu_load_test::instance_id); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) + { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } + } + + void on_message(const std::shared_ptr<vsomeip::message>& _request) + { + number_of_received_messages_++; + number_of_received_messages_total_++; + // send response + app_->send(vsomeip::runtime::get()->create_response(_request)); + } + + void on_message_start_measuring(const std::shared_ptr<vsomeip::message>& _request) + { + (void)_request; + load_measurer_.start(); + } + + void on_message_stop_measuring(const std::shared_ptr<vsomeip::message>& _request) + { + (void)_request; + load_measurer_.stop(); + VSOMEIP_DEBUG << "Received " << std::setw(4) << std::setfill('0') + << number_of_received_messages_ << " messages. CPU load [%]: " + << std::fixed << std::setprecision(2) + << (std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0); + results_.push_back(std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0); + number_of_received_messages_ = 0; + } + + void on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) + { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size())); + VSOMEIP_INFO << "Received: " << number_of_received_messages_total_ + << " in total (excluding control messages). This caused: " + << std::fixed << std::setprecision(2) + << average_load << "% load in average (average of " + << results_.size() << " measurements)."; + + std::vector<double> results_no_zero; + for(const auto &v : results_) { + if(v > 0.0) { + results_no_zero.push_back(v); + } + } + const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size())); + VSOMEIP_INFO << "Sent: " << number_of_received_messages_total_ + << " messages in total (excluding control messages). This caused: " + << std::fixed << std::setprecision(2) + << average_load_no_zero << "% load in average, if measured cpu load " + << "was greater zero (average of " + << results_no_zero.size() << " measurements)."; + stop(); + } + + void run() + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) { + condition_.wait(its_lock); + } + + app_->offer_service(cpu_load_test::service_id, cpu_load_test::instance_id); + } + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::uint32_t number_of_received_messages_total_; + cpu_load_measurer load_measurer_; + std::vector<double> results_; + std::thread offer_thread_; +}; + + +TEST(someip_payload_test, DISABLED_send_response_for_every_request) +{ + cpu_load_test_service test_service; + if (test_service.init()) { + test_service.start(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/CMakeLists.txt new file mode 100644 index 00000000000..761fb125a9f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +# Configure necessary files into the build folder. +set(configuration_files + service/vsomeip_events.json + service/vsomeip_gen.json + service/vsomeip_std.json + cyclic_event_test_client.json + cyclic_event_test_master_starter.sh + cyclic_event_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(cyclic_event_test_service + cyclic_event_test_service.cpp +) + +# Add test executable. +add_executable(cyclic_event_test_client + cyclic_event_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + cyclic_event_test_client + cyclic_event_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME cyclic_event_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/cyclic_event_test_master_starter.sh + TIMEOUT 15 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_client.json.in new file mode 100644 index 00000000000..5adaea3aa7b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_client.json.in @@ -0,0 +1,35 @@ +{ + "unicast": "@TEST_IP_SLAVE@", + "logging": { + "level": "debug", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/vsomeip.log" + }, + "dlt": "true" + }, + "applications": [ + { + "name": "client-sample", + "id": "0xbbbb" + } + ], + "clients": [ + { + "service": "0x1111", + "instance": "0x0001", + "unreliable": [ + 40000, + 40002 + ] + } + ], + "routing": "routingmanagerd", + "service-discovery": { + "enable": "true", + "multicast": "224.0.0.1", + "port": "30490", + "protocol": "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_master_starter.sh.in new file mode 100755 index 00000000000..e2799e2c689 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_master_starter.sh.in @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Configuration to be used by daemon and service. +export VSOMEIP_CONFIGURATION=service + +# Start the routing manager. +export VSOMEIP_APPLICATION_NAME="service-daemon" +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! + +# Start the test service. +export VSOMEIP_APPLICATION_NAME="service-sample" +./cyclic_event_test_service & +SERVICE_PID=$! + +# Start the test client. +if [ -n "$USE_LXC_TEST" ]; then + echo "starting cyclic_event_test_slave_starter.sh on slave LXC" + ssh -tt -i "$SANDBOX_ROOT_DIR"/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@"$LXC_TEST_SLAVE_IP" "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/cyclic_event_tests; ./cyclic_event_test_slave_starter.sh\"" & + echo "remote ssh job id: $!" +elif [ -n "$USE_DOCKER" ]; then + docker exec "$DOCKER_IMAGE" sh -c "cd $DOCKER_TESTS && ./cyclic_event_test_slave_starter.sh" & +else + cat <<EOF +******************************************************************************* +******************************************************************************* +** Please now run: +** cyclic_event_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** cyclic_event_test_client.json and +** cyclic_event_test_service.json to your personal setup. +******************************************************************************* +******************************************************************************* +EOF +fi + +# Whether the test failed. +FAIL=0 + +# Wait for the service to finish. +wait "$SERVICE_PID" || ((FAIL=1)) + +# Send a termination signal to the routing manager. +kill "$DAEMON_PID" + +# Wait for the routing manager to exit. +wait "$DAEMON_PID" + +# Return the result of the test. +exit "$FAIL" diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_service.json.in new file mode 100644 index 00000000000..8eb2fcf4001 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_service.json.in @@ -0,0 +1,46 @@ +{ + "unicast": "@TEST_IP_MASTER@", + "logging": { + "level": "debug", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/vsomeip.log" + }, + "dlt": "true" + }, + "applications": [ + { + "name": "service-sample", + "id": "0xaaaa" + } + ], + "services": [ + { + "service": "0x1111", + "instance": "0x0001", + "unreliable": "30509", + "events": [ + { + "event": "0x0002", + "cycle": 200 + } + ], + "eventgroups": [ + { + "eventgroup": "0x0001", + "events": [ + "0x0002" + ] + } + ] + } + ], + "routing": "routingmanagerd", + "service-discovery": { + "enable": "true", + "multicast": "224.0.0.1", + "port": "30490", + "protocol": "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_slave_starter.sh.in new file mode 100755 index 00000000000..35c28f841e9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/cyclic_event_test_slave_starter.sh.in @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Configuration to be used by daemon and service. +export VSOMEIP_CONFIGURATION=cyclic_event_test_client.json + +# Start the routing manager. +export VSOMEIP_APPLICATION_NAME="client-daemon" +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! + +# Start the test client. +export VSOMEIP_APPLICATION_NAME="client-sample" +./cyclic_event_test_client & +CLIENT_PID=$! + +# Whether the test failed. +FAIL=0 + +# Wait for the service to finish. +wait "$CLIENT_PID" || ((FAIL=1)) + +# Send a termination signal to the routing manager. +kill "$DAEMON_PID" + +# Wait for the routing manager to exit. +wait "$DAEMON_PID" + +# Return the result of the test. +exit "$FAIL" diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_events.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_events.json.in new file mode 100644 index 00000000000..0026a3907c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_events.json.in @@ -0,0 +1,23 @@ +{ + "services": [ + { + "service": "0x1111", + "instance": "0x0001", + "unreliable": "30509", + "events": [ + { + "event": "0x0002", + "cycle": 200 + } + ], + "eventgroups": [ + { + "eventgroup": "0x0001", + "events": [ + "0x0002" + ] + } + ] + } + ] +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_gen.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_gen.json.in new file mode 100644 index 00000000000..0fe1887c17a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_gen.json.in @@ -0,0 +1,9 @@ +{ + "services": [ + { + "service": "0x1111", + "instance": "0x0001", + "unreliable": "30509" + } + ] +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_std.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_std.json.in new file mode 100644 index 00000000000..a83ad19d13b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/conf/service/vsomeip_std.json.in @@ -0,0 +1,25 @@ +{ + "unicast": "@TEST_IP_MASTER@", + "logging": { + "level": "debug", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/vsomeip.log" + }, + "dlt": "true" + }, + "applications": [ + { + "name": "service-sample", + "id": "0xaaaa" + } + ], + "routing": "routingmanagerd", + "service-discovery": { + "enable": "true", + "multicast": "224.0.0.1", + "port": "30490", + "protocol": "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_client.cpp new file mode 100644 index 00000000000..ac289efdd18 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_client.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "cyclic_event_test_globals.hpp" + +using namespace cyclic_event_test; + +TEST(CyclicEventTest, ClientReceivesMultipleEvents) { + // Initialize the runtime. + auto runtime = vsomeip::runtime::get(); + ASSERT_TRUE(runtime) << "Should create a vsomeip runtime."; + + // Initialize the application. + auto application = runtime->create_application("client-sample"); + ASSERT_TRUE(application) << "Should create a vsomeip application."; + ASSERT_TRUE(application->init()) << "Should initialize application."; + + // Create a promise to shutdown the service. + std::promise<bool> shutdown_promise; + auto shutdown_future = shutdown_promise.get_future(); + + // Track amount of notifications that were received. + std::atomic_uint8_t notification_count {0}; + + // Handle an event notification. + application->register_message_handler( + SERVICE_ID, INSTANCE_ID, EVENT_ID, + [runtime, application, + ¬ification_count](const std::shared_ptr<vsomeip::message> /* message */) { + VSOMEIP_INFO << "Received event notification."; + + constexpr std::uint8_t MIN_NOTIFICATION_COUNT = 3; + if ((notification_count += 1) != MIN_NOTIFICATION_COUNT) { + return; + } + + auto shutdown_request = runtime->create_request(false); + shutdown_request->set_service(SERVICE_ID); + shutdown_request->set_instance(INSTANCE_ID); + shutdown_request->set_method(METHOD_ID); + shutdown_request->set_interface_version(MAJOR_VERSION); + application->send(shutdown_request); + }); + + // Handle shutdown response. + application->register_message_handler( + SERVICE_ID, INSTANCE_ID, METHOD_ID, + [&shutdown_promise](const std::shared_ptr<vsomeip::message> /* message */) { + VSOMEIP_INFO << "Received shutdown response."; + shutdown_promise.set_value(true); + }); + + // Request the test service. + application->request_service(SERVICE_ID, INSTANCE_ID, MAJOR_VERSION, MINOR_VERSION); + application->request_event(SERVICE_ID, INSTANCE_ID, EVENT_ID, {EVENTGROUP_ID}); + + // Subscribe to the test service when it becomes available. + application->register_availability_handler( + SERVICE_ID, INSTANCE_ID, + [application](vsomeip::service_t /* service */, vsomeip::instance_t /* instance */, + bool is_available) { + if (is_available) { + application->subscribe(SERVICE_ID, INSTANCE_ID, EVENTGROUP_ID, MAJOR_VERSION); + } + }, + MAJOR_VERSION, MINOR_VERSION); + + // Start the vsomeip application. + std::thread worker_thread([application] { application->start(); }); + + // Wait for the shutdown call. + shutdown_future.wait(); + application->stop(); + + // Clean up worker thread. + if (worker_thread.joinable()) { + worker_thread.join(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_globals.hpp new file mode 100644 index 00000000000..3184037b578 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_globals.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include <future> +#include <gtest/gtest.h> +#include <thread> +#include <vsomeip/internal/logger.hpp> +#include <vsomeip/vsomeip.hpp> + +namespace cyclic_event_test { + +// Unique identifier of the test service. +constexpr vsomeip::service_t SERVICE_ID = 0x1111; + +// Unique identifier of the test service instance. +constexpr vsomeip::instance_t INSTANCE_ID = 0x0001; + +// Major version of the test service interface. +constexpr vsomeip::major_version_t MAJOR_VERSION = 0x1; + +// Minor version of the test service interface. +constexpr vsomeip::minor_version_t MINOR_VERSION = 0x0; + +// Unique identifier of the method that triggers the shutdown of the service. +constexpr vsomeip::method_t METHOD_ID = 0x0001; + +// Unique identifier of the event offered by the service. +constexpr vsomeip::event_t EVENT_ID = 0x0002; + +// Unique identifier of the event group to which the event belongs. +constexpr vsomeip::eventgroup_t EVENTGROUP_ID = 0x0001; + +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_service.cpp new file mode 100644 index 00000000000..5ccb77733a3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/cyclic_event_tests/cyclic_event_test_service.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "cyclic_event_test_globals.hpp" + +using namespace cyclic_event_test; + +TEST(CyclicEventTest, ServiceNotifiesClient) { + // Initialize the runtime. + auto runtime = vsomeip::runtime::get(); + ASSERT_TRUE(runtime) << "Should create a vsomeip runtime."; + + // Initialize the application. + auto application = runtime->create_application("service-sample"); + ASSERT_TRUE(application) << "Should create a vsomeip application."; + ASSERT_TRUE(application->init()) << "Should initialize application."; + + // Create a promise to shutdown the service. + std::promise<bool> shutdown_promise; + auto shutdown_future = shutdown_promise.get_future(); + + // Handle a shutdown method call. + application->register_message_handler(SERVICE_ID, INSTANCE_ID, METHOD_ID, + [runtime, application, &shutdown_promise]( + const std::shared_ptr<vsomeip::message> message) { + VSOMEIP_INFO << "Received shutdown request."; + + auto response = runtime->create_response(message); + application->send(response); + + shutdown_promise.set_value(true); + }); + + // Offer the test service. + application->offer_service(SERVICE_ID, INSTANCE_ID, MAJOR_VERSION, MINOR_VERSION); + application->offer_event(SERVICE_ID, INSTANCE_ID, EVENT_ID, {EVENTGROUP_ID}, + vsomeip_v3::event_type_e::ET_FIELD); + + // Start the vsomeip application. + std::thread worker_thread([application] { application->start(); }); + + // Set the value of the event field. + auto payload = runtime->create_payload({0x01}); + application->notify(SERVICE_ID, INSTANCE_ID, EVENT_ID, payload); + + // Wait for the shutdown call. + shutdown_future.wait(); + + // Give the client a chance to exit cleanly. + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + application->stop(); + + // Clean up worker thread. + if (worker_thread.joinable()) { + worker_thread.join(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/CMakeLists.txt new file mode 100644 index 00000000000..dca6ddadcef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(debounce_callback_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + debounce_callback_test_client.json + debounce_callback_test_master_starter.sh + debounce_callback_test_service.json + debounce_callback_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(debounce_callback_test_client + debounce_callback_test_client.cpp +) + +# Add test executable. +add_executable(debounce_callback_test_service + debounce_callback_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + debounce_callback_test_client + debounce_callback_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME debounce_callback_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/debounce_callback_test_master_starter.sh + TIMEOUT 60 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_client.json.in new file mode 100644 index 00000000000..8cc0e690be0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_client.json.in @@ -0,0 +1,42 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "debounce" : + [ + { + "service" : "0xb657", + "instance" : "0x0003", + "events" : + [ + { + "event" : "0x8001", + "on_change" : "false", + "interval": 2000, + "send_current_value_after" : "true" + }, + { + "event" : "0x8002", + "on_change" : "false", + "interval": 3000, + "send_current_value_after" : "true" + } + ] + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_master_starter.sh.in new file mode 100755 index 00000000000..914b6ac26e8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_master_starter.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_callback_test_client.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_callback_test_client & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting debounce test on slave LXC debounce_callback_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/debounce_callback_tests; ./debounce_callback_test_slave_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./debounce_callback_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** debounce_callback_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** debounce_callback_test_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_service.json.in new file mode 100644 index 00000000000..78b939cf7c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_service.json.in @@ -0,0 +1,28 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "services" : + [ + { + "service" : "0xb657", + "instance" : "0x0003", + "unreliable" : "30503" + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_slave_starter.sh.in new file mode 100755 index 00000000000..8bf91b5a741 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/conf/debounce_callback_test_slave_starter.sh.in @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_callback_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +# Fail gets incremented if a client exits with a non-zero exit code +./debounce_callback_test_service || ((++FAIL)) + +# kill the services +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.cpp new file mode 100644 index 00000000000..8ba0df5df0f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.cpp @@ -0,0 +1,254 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_callback_test_client.hpp" + +static std::vector<std::shared_ptr<vsomeip::payload>> payloads__; + +debounce_test_client::debounce_test_client(int64_t _interval) : + interval(_interval), index_(0), is_available_(false), + runner_(std::bind(&debounce_test_client::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_timeout_test_client")) { } + +bool debounce_test_client::init() { + + bool its_result = app_->init(); + if (its_result) { + app_->register_availability_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, + std::bind(&debounce_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, vsomeip::ANY_EVENT, + std::bind(&debounce_test_client::on_message, this, std::placeholders::_1)); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT); + app_->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT_2); + } + return its_result; +} + +void debounce_test_client::start() { + + VSOMEIP_INFO << "Starting Client..."; + app_->start(); +} + +void debounce_test_client::stop() { + + VSOMEIP_INFO << "Stopping Client..."; + app_->stop(); +} + +void debounce_test_client::run() { + + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + while (!is_available_) { + auto its_status = run_condition_.wait_for(its_lock, std::chrono::milliseconds(15000)); + EXPECT_EQ(its_status, std::cv_status::no_timeout); + if (its_status == std::cv_status::timeout) { + VSOMEIP_ERROR << __func__ + << ": Debounce service did not become available after 15s."; + stop(); + return; + } + } + } + + VSOMEIP_INFO << __func__ << ": Running test."; + run_test(); + + unsubscribe_all(); + + VSOMEIP_INFO << __func__ << ": Stopping the service."; + stop_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + stop(); +} + +void debounce_test_client::wait() { + + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + if (_service == DEBOUNCE_SERVICE && _instance == DEBOUNCE_INSTANCE) { + + if (_is_available) { + VSOMEIP_ERROR << __func__ << ": Debounce service becomes available."; + { + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = true; + } + run_condition_.notify_one(); + } else { + VSOMEIP_ERROR << __func__ << ": Debounce service becomes unavailable."; + + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = false; + } + } +} + +void debounce_test_client::on_message(const std::shared_ptr<vsomeip::message>& _message) { + + std::stringstream s; + s << "RECV: "; + for (uint32_t i = 0; i < _message->get_payload()->get_length(); i++) { + s << std::hex << std::setw(2) << std::setfill('0') + << static_cast<int>(_message->get_payload()->get_data()[i]) << ' '; + } + VSOMEIP_DEBUG << s.str(); + + // Check if message received is equal to the one it was expecting + if (DEBOUNCE_SERVICE == _message->get_service() + && (DEBOUNCE_EVENT == _message->get_method() + || DEBOUNCE_EVENT_2 == _message->get_method())) { + bool is_equal = compare_payload(_message->get_payload(), index_++); + EXPECT_EQ(is_equal, true); + } +} + +bool debounce_test_client::compare_payload(const std::shared_ptr<vsomeip::payload>& _payload, + std::size_t _index) const { + + auto its_expected_payload = payloads__[_index]; + return (*_payload == *its_expected_payload); +} + +void debounce_test_client::run_test() { + + // Trigger the test + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_START_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); + + std::this_thread::sleep_for(std::chrono::seconds(23)); +} + +void debounce_test_client::unsubscribe_all() { + + app_->unsubscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP); +} + +void debounce_test_client::stop_service() { + + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_STOP_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); +} + +size_t debounce_test_client::getIndex() { + return index_; +} + +TEST(debounce_timeout_test, callback) { + // Interval time of 2 seconds + debounce_test_client its_client(2000); + ASSERT_TRUE(its_client.init()); + VSOMEIP_ERROR << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); + + // Check it got all messages + EXPECT_EQ(its_client.getIndex(), payloads__.size()); +} +int main(int argc, char** argv) { + + std::shared_ptr<vsomeip::payload> its_payload; + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0D}); + payloads__.push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0D}); + payloads__.push_back(its_payload); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.hpp new file mode 100644 index 00000000000..52c810a32eb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_client.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_CLIENT_HPP_ +#define DEBOUNCE_TEST_CLIENT_HPP_ + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_callback_test_common.hpp" + +class debounce_test_client { +public: + debounce_test_client(int64_t _interval); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + + size_t getIndex(); + +private: + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message>& _message); + + void run_test(); + void unsubscribe_all(); + void stop_service(); + + bool compare_payload(const std::shared_ptr<vsomeip::payload>& _payload, + std::size_t _index) const; + +private: + int64_t interval; + + size_t index_; + + bool is_available_; + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; +}; + +#endif // DEBOUNCE_CALLBACK_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_common.hpp new file mode 100644 index 00000000000..12aa9ccbb60 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_common.hpp @@ -0,0 +1,21 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_COMMON_HPP_ +#define DEBOUNCE_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t DEBOUNCE_SERVICE = 0xb657; +const vsomeip::instance_t DEBOUNCE_INSTANCE = 0x0003; +const vsomeip::method_t DEBOUNCE_START_METHOD = 0x0998; +const vsomeip::method_t DEBOUNCE_STOP_METHOD = 0x0999; +const vsomeip::event_t DEBOUNCE_EVENT = 0x8001; +const vsomeip::event_t DEBOUNCE_EVENT_2 = 0x8002; +const vsomeip::eventgroup_t DEBOUNCE_EVENTGROUP = 0x0005; +const vsomeip::major_version_t DEBOUNCE_MAJOR = 0x01; +const vsomeip::minor_version_t DEBOUNCE_MINOR = 0x01; + +#endif // DEBOUNCE_CALLBACK_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.cpp new file mode 100644 index 00000000000..f67366f5e19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.cpp @@ -0,0 +1,168 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_callback_test_service.hpp" + +debounce_test_service::debounce_test_service() : + runner_(std::bind(&debounce_test_service::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_timeout_test_service")) { } + +bool debounce_test_service::init() { + + bool is_initialized = app_->init(); + if (is_initialized) { + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_START_METHOD, + std::bind(&debounce_test_service::on_start, this, std::placeholders::_1)); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_STOP_METHOD, + std::bind(&debounce_test_service::on_stop, this, std::placeholders::_1)); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + } + return is_initialized; +} + +void debounce_test_service::start() { + + VSOMEIP_INFO << "Starting Service..."; + app_->start(); +} + +void debounce_test_service::stop() { + + VSOMEIP_INFO << "Stopping Service..."; + app_->stop(); +} + +void debounce_test_service::run() { + + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + auto its_result = run_condition_.wait_for(its_lock, std::chrono::milliseconds(5000)); + if (its_result == std::cv_status::timeout) + return; + } + + start_test(); +} + +void debounce_test_service::wait() { + + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_service::on_start(const std::shared_ptr<vsomeip::message>& _message) { + + (void)_message; + + VSOMEIP_INFO << __func__ << ": Starting test"; + run_condition_.notify_one(); +} + +void debounce_test_service::on_stop(const std::shared_ptr<vsomeip::message>& _message) { + + (void)_message; + + VSOMEIP_INFO << __func__ << ": Received a STOP command."; + stop(); +} + +void debounce_test_service::start_test() { + + auto its_payload = vsomeip::runtime::get()->create_payload(); + + // To check if debouncer send the last message after timeout + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent first message!"; + std::this_thread::sleep_for(std::chrono::seconds(1)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent second message!"; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // To check normal function of the debouncer + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent third message!"; + std::this_thread::sleep_for(std::chrono::seconds(3)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent fourth message!"; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // To check only one message is forwarded after timeout + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent fifth message!"; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent sixth message!"; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent seventh message!"; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // To check the interaction when two events use the debounce + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent eight message!"; + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + VSOMEIP_INFO << "Sent first event 2 message!"; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent ninth message!"; + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + VSOMEIP_INFO << "Sent second event 2 message!"; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + its_payload->set_data({0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + VSOMEIP_INFO << "Sent tenth message!"; + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + VSOMEIP_INFO << "Sent third event 2 message!"; + + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // Testing with lots of messages + + VSOMEIP_INFO << "Sending lot of messages!"; + for (int i = 0; i < 30; i++) { + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, (unsigned char)(i % 16)}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } +} + +TEST(debounce_timeout_test, callback) { + debounce_test_service its_service; + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +int main(int argc, char** argv) { + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.hpp new file mode 100644 index 00000000000..ba418c16d88 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_callback_tests/debounce_callback_test_service.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_SERVICE_HPP_ +#define DEBOUNCE_TEST_SERVICE_HPP_ + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_callback_test_common.hpp" + +class debounce_test_service { +public: + debounce_test_service(); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + +private: + void on_start(const std::shared_ptr<vsomeip::message>& _message); + void on_stop(const std::shared_ptr<vsomeip::message>& _message); + + void start_test(); + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; +}; + +#endif // DEBOUNCE_CALLBACK_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/CMakeLists.txt new file mode 100644 index 00000000000..af116fc4e9a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(debounce_filter_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + debounce_filter_test_client.json + debounce_filter_test_master_starter.sh + debounce_filter_test_service.json + debounce_filter_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(debounce_filter_test_client + debounce_filter_test_client.cpp +) + +# Add test executable. +add_executable(debounce_filter_test_service + debounce_filter_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + debounce_filter_test_client + debounce_filter_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME debounce_filter_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/debounce_filter_test_master_starter.sh +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_client.json.in new file mode 100644 index 00000000000..aa781685bbf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_client.json.in @@ -0,0 +1,40 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "tracing" : + { + "enable" : "true" + }, + "debounce" : + [ + { + "service" : "0xb519", + "instance" : "0x0001", + "events" : + [ + { + "event" : "0x8008", + "on_change" : "false", + "ignore" : + [] + } + ] + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_master_starter.sh.in new file mode 100755 index 00000000000..e85e010084b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_master_starter.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_filter_test_client.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_filter_test_client & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting debounce_filter test on slave LXC debounce_filter_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/debounce_filter_tests; ./debounce_filter_test_slave_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./debounce_filter_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** debounce_filter_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** debounce_filter_test_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_service.json.in new file mode 100644 index 00000000000..caacc1f8e09 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_service.json.in @@ -0,0 +1,32 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "tracing" : + { + "enable" : "true" + }, + "services" : + [ + { + "service" : "0xb519", + "instance" : "0x0001", + "unreliable" : "30503" + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_slave_starter.sh.in new file mode 100755 index 00000000000..a462ba268b5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/conf/debounce_filter_test_slave_starter.sh.in @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_filter_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_filter_test_service & +PID_SLAVE=$! + +# Wait until all slaves are finished +for job in $PID_SLAVE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.cpp new file mode 100644 index 00000000000..4cc33a41280 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.cpp @@ -0,0 +1,215 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_filter_test_client.hpp" + +static std::vector<std::vector<std::shared_ptr<vsomeip::payload>>> payloads__; + +debounce_test_client::debounce_test_client(int64_t _interval) : + interval(_interval), index_(0), is_available_(false), + runner_(std::bind(&debounce_test_client::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_test_client")), sum_time(0) { } + +bool debounce_test_client::init() { + dBFilter.interval_ = interval; + + bool its_result = app_->init(); + if (its_result) { + app_->register_availability_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, + std::bind(&debounce_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, vsomeip::ANY_EVENT, + std::bind(&debounce_test_client::on_message, this, std::placeholders::_1)); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->subscribe_with_debounce(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, + DEBOUNCE_MAJOR, DEBOUNCE_EVENT, dBFilter); + } + return its_result; +} + +void debounce_test_client::start() { + VSOMEIP_INFO << "Starting Client..."; + app_->start(); +} + +void debounce_test_client::stop() { + VSOMEIP_INFO << "Stopping Client..."; + app_->stop(); +} + +void debounce_test_client::run() { + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + while (!is_available_) { + auto its_status = run_condition_.wait_for(its_lock, std::chrono::milliseconds(15000)); + EXPECT_EQ(its_status, std::cv_status::no_timeout); + if (its_status == std::cv_status::timeout) { + VSOMEIP_ERROR << __func__ + << ": Debounce service did not become available after 15s."; + stop(); + return; + } + } + } + + VSOMEIP_INFO << __func__ << ": Running test."; + run_test(); + + unsubscribe_all(); + + VSOMEIP_INFO << __func__ << ": Stopping the service."; + stop_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + stop(); +} + +void debounce_test_client::wait() { + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if (_service == DEBOUNCE_SERVICE && _instance == DEBOUNCE_INSTANCE) { + + if (_is_available) { + VSOMEIP_INFO << __func__ << ": Debounce service becomes available."; + { + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = true; + } + run_condition_.notify_one(); + } else { + VSOMEIP_INFO << __func__ << ": Debounce service becomes unavailable."; + + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = false; + } + } +} + +void debounce_test_client::on_message(const std::shared_ptr<vsomeip::message>& _message) { + if (!nb_msgs_rcvd) { + time_start = std::chrono::high_resolution_clock::now(); + time_last = time_start; + } else { + time_last = std::chrono::high_resolution_clock::now(); + } + + std::stringstream s; + s << "RECV: "; + for (uint32_t i = 0; i < _message->get_payload()->get_length(); i++) { + s << std::hex << std::setw(3) << std::setfill('0') + << static_cast<int>(_message->get_payload()->get_data()[i]) << " "; + } + + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT == _message->get_method()) { + nb_msgs_rcvd++; + s << "\t- Message: " << std::dec << std::setw(2) << nb_msgs_rcvd; + + if (nb_msgs_rcvd >= 2) { + std::chrono::duration elapsed_time_ms = (time_last - time_start); + sum_time += std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time_ms); + s << " Average interval is " << get_avgtime().count() << " ms"; + } + VSOMEIP_DEBUG << s.str(); + s.clear(); + } + time_start = time_last; +} + +void debounce_test_client::run_test() { + // Trigger the test + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_START_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); + + std::this_thread::sleep_for(std::chrono::seconds(15)); +} + +void debounce_test_client::unsubscribe_all() { + app_->unsubscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP); +} + +void debounce_test_client::stop_service() { + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_STOP_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); +} + +int64_t debounce_test_client::getNbMsgsRcvd() { + return nb_msgs_rcvd; +} + +std::chrono::milliseconds debounce_test_client::get_avgtime() { + return (sum_time / (getNbMsgsRcvd() - 1)); +} + +TEST(debounce_test, normal_interval) { + debounce_test_client its_client(DEBOUNCE_INTERVAL_1); + ASSERT_TRUE(its_client.init()); + VSOMEIP_INFO << "Debounce client successfully initialized!"; + its_client.start(); + its_client.wait(); + + // Average Interval should be between 95ms and 105ms + EXPECT_GE(its_client.get_avgtime().count(), (double)DEBOUNCE_INTERVAL_1 - 5); + EXPECT_LE(its_client.get_avgtime().count(), (double)DEBOUNCE_INTERVAL_1 + 5); +} + +TEST(debounce_test, large_interval) { + debounce_test_client its_client(DEBOUNCE_INTERVAL_2); + ASSERT_TRUE(its_client.init()); + VSOMEIP_INFO << "Debounce client successfully initialized!"; + its_client.start(); + its_client.wait(); + + // Average Interval should be between 995ms and 1005ms + EXPECT_GE(its_client.get_avgtime().count(), (double)DEBOUNCE_INTERVAL_2 - 5); + EXPECT_LE(its_client.get_avgtime().count(), (double)DEBOUNCE_INTERVAL_2 + 5); +} + +TEST(debounce_test, disable) { + debounce_test_client its_client(DEBOUNCE_INTERVAL_3); + ASSERT_TRUE(its_client.init()); + VSOMEIP_INFO << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); + + // With a debounce interval disabled (-1), the client is expected to not receive any message + EXPECT_EQ(its_client.getNbMsgsRcvd(), 0); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.hpp new file mode 100644 index 00000000000..ba58b14c1b5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_client.hpp @@ -0,0 +1,62 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_CLIENT_HPP_ +#define DEBOUNCE_TEST_CLIENT_HPP_ + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_filter_test_common.hpp" + +class debounce_test_client { +public: + debounce_test_client(int64_t _interval); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + + int64_t getNbMsgsRcvd(); + std::chrono::milliseconds get_avgtime(); + +private: + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message>& _message); + + void run_test(); + void unsubscribe_all(); + void stop_service(); + +private: + int64_t interval; + size_t index_; + + bool is_available_; + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; + + vsomeip::debounce_filter_t dBFilter; + + int64_t nb_msgs_rcvd = 0; + std::chrono::milliseconds sum_time; + std::chrono::time_point<std::chrono::high_resolution_clock> time_start; + std::chrono::time_point<std::chrono::high_resolution_clock> time_last; +}; + +#endif // DEBOUNCE_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_common.hpp new file mode 100644 index 00000000000..79f3c40d2a5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_common.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_COMMON_HPP_ +#define DEBOUNCE_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t DEBOUNCE_SERVICE = 0xb519; +const vsomeip::instance_t DEBOUNCE_INSTANCE = 0x0001; +const vsomeip::method_t DEBOUNCE_START_METHOD = 0x0998; +const vsomeip::method_t DEBOUNCE_STOP_METHOD = 0x0999; +const vsomeip::event_t DEBOUNCE_EVENT = 0x8008; +const vsomeip::eventgroup_t DEBOUNCE_EVENTGROUP = 0x0005; +const vsomeip::major_version_t DEBOUNCE_MAJOR = 0x01; +const vsomeip::minor_version_t DEBOUNCE_MINOR = 0x01; + +const int64_t DEBOUNCE_INTERVAL_1 = 100; +const int64_t DEBOUNCE_INTERVAL_2 = 1000; +const int64_t DEBOUNCE_INTERVAL_3 = -1; + +#endif // DEBOUNCE_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.cpp new file mode 100644 index 00000000000..8993af5ab8e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_filter_test_service.hpp" + +debounce_test_service::debounce_test_service() : + is_running_(true), runner_(std::bind(&debounce_test_service::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_test_service")) { } + +bool debounce_test_service::init() { + bool is_initialized = app_->init(); + if (is_initialized) { + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_START_METHOD, + std::bind(&debounce_test_service::on_start, this, std::placeholders::_1)); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_STOP_METHOD, + std::bind(&debounce_test_service::on_stop, this, std::placeholders::_1)); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + } + return is_initialized; +} + +void debounce_test_service::start() { + VSOMEIP_INFO << "Starting Service..."; + app_->start(); +} + +void debounce_test_service::stop() { + VSOMEIP_INFO << "Stopping Service..."; + app_->stop(); +} + +void debounce_test_service::run() { + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + auto its_result = run_condition_.wait_for(its_lock, std::chrono::milliseconds(5000)); + if (its_result == std::cv_status::timeout) + return; + } + + start_test(); +} + +void debounce_test_service::wait() { + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_service::on_start(const std::shared_ptr<vsomeip::message>&) { + VSOMEIP_INFO << __func__ << ": Starting test"; + run_condition_.notify_one(); +} + +void debounce_test_service::on_stop(const std::shared_ptr<vsomeip::message>&) { + VSOMEIP_INFO << __func__ << ": Received a STOP command."; + is_running_ = false; + stop(); +} + +void debounce_test_service::start_test() { + auto its_payload = vsomeip::runtime::get()->create_payload(); + + for (int i = 0; i <= 1000; i++) { + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } +} + +TEST(debounce_test, normal_interval) { + debounce_test_service its_service; + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +TEST(debounce_test, large_interval) { + debounce_test_service its_service; + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +TEST(debounce_test, disable) { + debounce_test_service its_service; + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.hpp new file mode 100644 index 00000000000..0b4dde64387 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_filter_tests/debounce_filter_test_service.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_SERVICE_HPP_ +#define DEBOUNCE_TEST_SERVICE_HPP_ + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_filter_test_common.hpp" + +class debounce_test_service { +public: + debounce_test_service(); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + +private: + void on_start(const std::shared_ptr<vsomeip::message>&); + void on_stop(const std::shared_ptr<vsomeip::message>&); + + void start_test(); + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::atomic<bool> is_running_; + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; +}; + +#endif // DEBOUNCE_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/CMakeLists.txt new file mode 100644 index 00000000000..28206ac882f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(debounce_frequency_test LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + debounce_frequency_test_client.json + debounce_frequency_test_master_starter.sh + debounce_frequency_test_service.json + debounce_frequency_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(debounce_frequency_test_client + debounce_frequency_test_client.cpp +) + +# Add test executable. +add_executable(debounce_frequency_test_service + debounce_frequency_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + debounce_frequency_test_client + debounce_frequency_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME debounce_frequency_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/debounce_frequency_test_master_starter.sh + TIMEOUT 60 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_client.json.in new file mode 100644 index 00000000000..3281c47c4d8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_client.json.in @@ -0,0 +1,37 @@ +{ + "unicast": "@TEST_IP_MASTER@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "debounce": [ + { + "service": "0xb657", + "instance": "0x0003", + "events": [ + { + "event": "0x8001", + "on_change": "false", + "interval": 5000 + }, + { + "event": "0x8002", + "on_change": "false", + "interval": 5000 + } + ] + } + ], + "service-discovery": { + "enable": "true", + "multicast": "224.251.192.252", + "port": "30490", + "protocol": "udp", + "cyclic_offer_delay": "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_master_starter.sh.in new file mode 100755 index 00000000000..e372519cd35 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_master_starter.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_frequency_test_client.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_frequency_test_client & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting debounce test on slave LXC debounce_frequency_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/debounce_frequency_tests; ./debounce_frequency_test_slave_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./debounce_frequency_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** debounce_frequency_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** debounce_frequency_test_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_service.json.in new file mode 100644 index 00000000000..78b939cf7c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_service.json.in @@ -0,0 +1,28 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "services" : + [ + { + "service" : "0xb657", + "instance" : "0x0003", + "unreliable" : "30503" + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_slave_starter.sh.in new file mode 100755 index 00000000000..2bd5a89c8af --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/conf/debounce_frequency_test_slave_starter.sh.in @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_frequency_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +if ! ./debounce_frequency_test_service +then + # Fail gets incremented if a client exits with a non-zero exit code + FAIL=$(($FAIL+1)) +fi + +# kill the services +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.cpp new file mode 100644 index 00000000000..4467b10fee5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_frequency_test_client.hpp" + +// Flag the desired event availability +void test_client::on_availability(vsomeip::service_t service_, vsomeip::instance_t instance_, + bool _is_available) { + if (_is_available && service_ == DEBOUNCE_SERVICE && instance_ == DEBOUNCE_INSTANCE) { + std::unique_lock<std::mutex> lk(mutex); + availability = true; + condition_availability.notify_one(); + } +} + +// When a message is received, verify if it is one of the required events +void test_client::on_message(const std::shared_ptr<vsomeip::message>& _message) { + std::stringstream s; + s << "RECV: "; + for (uint32_t i = 0; i < _message->get_payload()->get_length(); i++) { + s << std::hex << std::setw(2) << std::setfill('0') + << static_cast<int>(_message->get_payload()->get_data()[i]) << " "; + } + VSOMEIP_DEBUG << s.str(); + + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT == _message->get_method()) { + std::unique_lock<std::mutex> lk(event_counter_mutex); + event_1_recv_messages++; + return; + } + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT_2 == _message->get_method()) { + std::unique_lock<std::mutex> lk(event_counter_mutex); + event_2_recv_messages++; + return; + } +} + +test_client::test_client(const char* app_name_, const char* app_id_) : + vsomeip_utilities::base_vsip_app(app_name_, app_id_) { + _app->register_availability_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, + std::bind(&test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + _app->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, vsomeip::ANY_EVENT, + std::bind(&test_client::on_message, this, std::placeholders::_1)); + _app->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, {DEBOUNCE_EVENTGROUP}, + vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + _app->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + _app->request_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + _app->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT); + _app->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT_2); +} + +int test_client::was_event1_recv() { + std::unique_lock<std::mutex> lk(event_counter_mutex); + + return event_1_recv_messages; +} + +int test_client::was_event2_recv() { + std::unique_lock<std::mutex> lk(event_counter_mutex); + + return event_2_recv_messages; +} + +void test_client::send_request() { + std::unique_lock<std::mutex> lk(mutex); + // Only send the requests when the service availability is secured + if (condition_availability.wait_for(lk, std::chrono::milliseconds(15000), + [=] { return availability; })) { + + // Trigger the test + auto its_message = vsomeip_utilities::create_standard_vsip_request( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_START_METHOD, DEBOUNCE_MAJOR, + vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + _app->send(its_message); + } + + EXPECT_TRUE(availability) << "Events expected by the client were not available for 15 seconds "; + + // Wait for Server to send all the messages + std::this_thread::sleep_for(std::chrono::seconds(10)); +} + +void test_client::unsubscribe_all() { + _app->unsubscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP); +} + +void test_client::stop_service() { + auto its_message = vsomeip_utilities::create_standard_vsip_request( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_STOP_METHOD, DEBOUNCE_MAJOR, + vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + _app->send(its_message); +} + +test_client::~test_client() { + unsubscribe_all(); + stop_service(); +} + +TEST(debounce_frequency_test, client) { + test_client debounce_client("debounce_frequency_test_client", "DFTC"); + // Request the server to send the test messages + debounce_client.send_request(); + + ASSERT_EQ(debounce_client.was_event1_recv(), 1) + << "Event 1 expected to be received once by the client, instead it was received " + << debounce_client.was_event1_recv() << " times."; + ASSERT_EQ(debounce_client.was_event2_recv(), 1) + << "Event 2 expected to be received once by the client, instead it was received " + << debounce_client.was_event2_recv() << " times."; +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.hpp new file mode 100644 index 00000000000..4b0c12c0c6b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_client.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_FREQUENCY_TEST_CLIENT_HPP_ +#define DEBOUNCE_FREQUENCY_TEST_CLIENT_HPP_ + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_frequency_test_common.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class test_client : public vsomeip_utilities::base_vsip_app { + +private: + std::condition_variable condition_availability; + std::mutex mutex; + std::mutex event_counter_mutex; + bool availability {false}; + + int event_1_recv_messages {0}; + int event_2_recv_messages {0}; + + void on_availability(vsomeip::service_t service_, vsomeip::instance_t instance_, + bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message>& _message); + void stop_service(); + void unsubscribe_all(); + +public: + test_client(const char* app_name_, const char* app_id_); + + int was_event1_recv(); + int was_event2_recv(); + void send_request(); + ~test_client(); +}; + +#endif // DEBOUNCE_FREQUENCY_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_common.hpp new file mode 100644 index 00000000000..2531929dd4e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_common.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_FREQUENCY_TEST_COMMON_HPP_ +#define DEBOUNCE_FREQUENCY_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t DEBOUNCE_SERVICE = 0xb657; +const vsomeip::instance_t DEBOUNCE_INSTANCE = 0x0003; +const vsomeip::method_t DEBOUNCE_START_METHOD = 0x0998; +const vsomeip::method_t DEBOUNCE_STOP_METHOD = 0x0999; +const vsomeip::event_t DEBOUNCE_EVENT = 0x8001; +const vsomeip::event_t DEBOUNCE_EVENT_2 = 0x8002; +const vsomeip::eventgroup_t DEBOUNCE_EVENTGROUP = 0x0005; +const vsomeip::major_version_t DEBOUNCE_MAJOR = 0x01; +const vsomeip::minor_version_t DEBOUNCE_MINOR = 0x01; + +enum debounce_frequency_test_id_e : uint8_t { + DTI_FLAT = 0x00, +}; + +#endif // DEBOUNCE_FREQUENCY_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.cpp new file mode 100644 index 00000000000..587778b77f3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> +#include "debounce_frequency_test_service.hpp" + +uint64_t +elapsedMilliseconds(const std::chrono::time_point<std::chrono::system_clock>& _start_time) { + return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() + - _start_time) + .count(); +} + +void test_service::on_start(const std::shared_ptr<vsomeip::message> /*&_message*/) { + std::unique_lock<std::mutex> lk(mutex); + received_message = true; + condition_wait_start.notify_one(); +} + +void test_service::on_stop(const std::shared_ptr<vsomeip::message> /*&_message*/) { + VSOMEIP_INFO << "service: " << __func__ << ": Received a STOP command."; +} + +test_service::test_service(const char* app_name_, const char* app_id_) : + vsomeip_utilities::base_vsip_app(app_name_, app_id_) { + _app->register_message_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_START_METHOD, + std::bind(&test_service::on_start, this, std::placeholders::_1)); + _app->register_message_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_STOP_METHOD, + std::bind(&test_service::on_stop, this, std::placeholders::_1)); + _app->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, {DEBOUNCE_EVENTGROUP}, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), false, + true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + _app->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, {DEBOUNCE_EVENTGROUP}, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), false, + true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + _app->offer_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); +} + +// Send the debounce events with different frequencies, but configured with the same debounce time +void test_service::send_messages() { + std::unique_lock<std::mutex> lk(mutex); + if (condition_wait_start.wait_for(lk, std::chrono::milliseconds(2000), + [=] { return received_message; })) { + + VSOMEIP_INFO << "service: " << __func__ << ": Starting test "; + start_time = std::chrono::system_clock::now(); + uint8_t i = 0; + while (elapsedMilliseconds(start_time) < 3000) { + + if (elapsedMilliseconds(start_time) % 30 == 0) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, i++}); + + _app->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + event_1_sent_messages = true; + } + + if (elapsedMilliseconds(start_time) % 2 == 0) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, i++}); + _app->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + event_2_sent_messages = true; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } +} + +bool test_service::was_event_1_sent() { + return event_1_sent_messages; +} + +bool test_service::was_event_2_sent() { + return event_2_sent_messages; +} + +TEST(debounce_frequency_test, server) { + test_service debounce_server("debounce_frequency_test_service", "DFTS"); + debounce_server.send_messages(); + + EXPECT_TRUE(debounce_server.was_event_1_sent()) << "Event 1 was not sent by the service"; + EXPECT_TRUE(debounce_server.was_event_2_sent()) << "Event 2 was not sent by the service"; +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.hpp new file mode 100644 index 00000000000..6efc44b695a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_frequency_tests/debounce_frequency_test_service.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_FREQUENCY_TEST_SERVICE_HPP_ +#define DEBOUNCE_FREQUENCY_TEST_SERVICE_HPP_ + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_frequency_test_common.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class test_service : public vsomeip_utilities::base_vsip_app { +private: + std::condition_variable condition_wait_start; + std::mutex mutex; + bool received_message {false}; + std::chrono::time_point<std::chrono::system_clock> start_time; + bool event_1_sent_messages {false}; + bool event_2_sent_messages {false}; + + void on_start(const std::shared_ptr<vsomeip::message> /*&_message*/); + void on_stop(const std::shared_ptr<vsomeip::message> /*&_message*/); + +public: + test_service(const char* app_name_, const char* app_id_); + + void send_messages(); + bool was_event_1_sent(); + bool was_event_2_sent(); +}; + +#endif // debounce_frequency_test_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/CMakeLists.txt new file mode 100644 index 00000000000..1e314352e56 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(debounce_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + debounce_test_client.json + debounce_test_master_starter.sh + debounce_test_service.json + debounce_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(debounce_test_client + debounce_test_client.cpp +) + +# Add test executable. +add_executable(debounce_test_service + debounce_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + debounce_test_client + debounce_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME debounce_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/debounce_test_master_starter.sh + TIMEOUT 60 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_client.json.in new file mode 100644 index 00000000000..77884e07c22 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_client.json.in @@ -0,0 +1,61 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "debounce" : + [ + { + "service" : "0xb657", + "instance" : "0x0003", + "events" : + [ + { + "event" : "0x8001", + "on_change" : "true", + "ignore" : + [ + 0, 5 + ] + }, + { + "event" : "0x8002", + "on_change" : "true", + "ignore" : + [ + 0, 5, 7, 8, 9, 10 + ] + }, + { + "event" : "0x8004", + "on_change" : "true", + "ignore" : + [ + { + "index" : "0", + "mask" : "0x0f" + }, + { + "index" : "5", + "mask" : "0xfe" + } + ] + } + ] + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_master_starter.sh.in new file mode 100755 index 00000000000..749e131c632 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_master_starter.sh.in @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_test_client.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_test_client & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting debounce test on slave LXC debounce_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/debounce_tests; ./debounce_test_slave_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./debounce_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** debounce_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** debounce_test_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_service.json.in new file mode 100644 index 00000000000..78b939cf7c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_service.json.in @@ -0,0 +1,28 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging": { + "level": "info", + "console": "true", + "file": { + "enable": "false", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "services" : + [ + { + "service" : "0xb657", + "instance" : "0x0003", + "unreliable" : "30503" + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_slave_starter.sh.in new file mode 100755 index 00000000000..89b598243d5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/conf/debounce_test_slave_starter.sh.in @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=debounce_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +./debounce_test_service & +PID_SLAVE=$! + +# Wait until all slaves are finished +for job in $PID_SLAVE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.cpp new file mode 100644 index 00000000000..7ad2b606743 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.cpp @@ -0,0 +1,363 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_test_client.hpp" + +static std::vector<std::vector<std::shared_ptr<vsomeip::payload>>> payloads__; + +debounce_test_client::debounce_test_client(debounce_test_id_e _test_id) : + test_id_(_test_id), index_(0), is_available_(false), + runner_(std::bind(&debounce_test_client::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_test_client")) { } + +bool debounce_test_client::init() { + + bool its_result = app_->init(); + if (its_result) { + app_->register_availability_handler(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, + std::bind(&debounce_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, vsomeip::ANY_EVENT, + std::bind(&debounce_test_client::on_message, this, std::placeholders::_1)); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + app_->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT); + app_->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT_2); + app_->subscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP, DEBOUNCE_MAJOR, + DEBOUNCE_EVENT_4); + } + return its_result; +} + +void debounce_test_client::start() { + + VSOMEIP_INFO << "Starting Client..."; + app_->start(); +} + +void debounce_test_client::stop() { + + VSOMEIP_INFO << "Stopping Client..."; + app_->stop(); +} + +void debounce_test_client::run() { + + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + while (!is_available_) { + auto its_status = run_condition_.wait_for(its_lock, std::chrono::milliseconds(15000)); + EXPECT_EQ(its_status, std::cv_status::no_timeout); + if (its_status == std::cv_status::timeout) { + VSOMEIP_ERROR << __func__ + << ": Debounce service did not become available after 15s."; + stop(); + return; + } + } + } + + VSOMEIP_INFO << __func__ << ": Running test."; + run_test(); + + unsubscribe_all(); + + VSOMEIP_INFO << __func__ << ": Stopping the service."; + stop_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + stop(); +} + +void debounce_test_client::wait() { + + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + if (_service == DEBOUNCE_SERVICE && _instance == DEBOUNCE_INSTANCE) { + + if (_is_available) { + VSOMEIP_ERROR << __func__ << ": Debounce service becomes available."; + { + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = true; + } + run_condition_.notify_one(); + } else { + VSOMEIP_ERROR << __func__ << ": Debounce service becomes unavailable."; + + std::lock_guard<std::mutex> its_lock(run_mutex_); + is_available_ = false; + } + } +} + +void debounce_test_client::on_message(const std::shared_ptr<vsomeip::message>& _message) { + + std::stringstream s; + s << "RECV: "; + for (uint32_t i = 0; i < _message->get_payload()->get_length(); i++) { + s << std::hex << std::setw(2) << std::setfill('0') + << static_cast<int>(_message->get_payload()->get_data()[i]) << " "; + } + VSOMEIP_DEBUG << s.str(); + + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT == _message->get_method()) { + + if (test_id_ == debounce_test_id_e::DTI_FLAT) { + bool is_equal = compare_payload(_message->get_payload(), index_++); + EXPECT_EQ(is_equal, true); + if (!is_equal || index_ == 5) + run_condition_.notify_one(); + } + + return; + } + + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT_2 == _message->get_method()) { + + if (test_id_ == debounce_test_id_e::DTI_INCREASE + || test_id_ == debounce_test_id_e::DTI_DECREASE) { + bool is_equal = compare_payload(_message->get_payload(), index_++); + EXPECT_EQ(is_equal, true); + + if (!is_equal || index_ == 6) + run_condition_.notify_one(); + } + + return; + } + + if (DEBOUNCE_SERVICE == _message->get_service() && DEBOUNCE_EVENT_4 == _message->get_method()) { + + if (test_id_ == debounce_test_id_e::DTI_MASK) { + bool is_equal = compare_payload(_message->get_payload(), index_++); + EXPECT_EQ(is_equal, true); + + if (!is_equal || index_ == 6) + run_condition_.notify_one(); + } + + return; + } +} + +bool debounce_test_client::compare_payload(const std::shared_ptr<vsomeip::payload>& _payload, + std::size_t _index) const { + + auto its_expected_payload = payloads__[test_id_][_index]; + return (*_payload == *its_expected_payload); +} + +void debounce_test_client::run_test() { + + // Trigger the test + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_START_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); + + // Wait for the result + std::unique_lock<std::mutex> its_lock(run_mutex_); + if (!is_available_) { + auto its_result = run_condition_.wait_for(its_lock, std::chrono::milliseconds(5000)); + + EXPECT_EQ(its_result, std::cv_status::no_timeout); + } + + std::this_thread::sleep_for(std::chrono::seconds(2)); +} + +void debounce_test_client::unsubscribe_all() { + + app_->unsubscribe(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENTGROUP); +} + +void debounce_test_client::stop_service() { + + auto its_runtime = vsomeip::runtime::get(); + auto its_payload = its_runtime->create_payload(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(DEBOUNCE_SERVICE); + its_message->set_instance(DEBOUNCE_INSTANCE); + its_message->set_method(DEBOUNCE_STOP_METHOD); + its_message->set_interface_version(DEBOUNCE_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(its_payload); + app_->send(its_message); +} + +TEST(debounce_test, flat) { + debounce_test_client its_client(debounce_test_id_e::DTI_FLAT); + ASSERT_TRUE(its_client.init()); + VSOMEIP_ERROR << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); +} + +TEST(debounce_test, increase) { + debounce_test_client its_client(debounce_test_id_e::DTI_INCREASE); + ASSERT_TRUE(its_client.init()); + VSOMEIP_ERROR << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); +} + +TEST(debounce_test, decrease) { + debounce_test_client its_client(debounce_test_id_e::DTI_DECREASE); + ASSERT_TRUE(its_client.init()); + VSOMEIP_ERROR << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); +} + +TEST(debounce_test, mask) { + debounce_test_client its_client(debounce_test_id_e::DTI_MASK); + ASSERT_TRUE(its_client.init()); + VSOMEIP_ERROR << "Debounce Client successfully initialized!"; + its_client.start(); + its_client.wait(); +} + +int main(int argc, char** argv) { + + std::shared_ptr<vsomeip::payload> its_payload; + + // Flat test + payloads__.push_back(std::vector<std::shared_ptr<vsomeip::payload>>()); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_FLAT].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_FLAT].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_FLAT].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_FLAT].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_FLAT].push_back(its_payload); + + // Increase test + payloads__.push_back(std::vector<std::shared_ptr<vsomeip::payload>>()); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07, 0x08}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07, 0x08, 0x09}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07, 0x08, 0x09, 0x0A}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x09, 0x02, 0x03, 0x04, 0x01, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}); + payloads__[debounce_test_id_e::DTI_INCREASE].push_back(its_payload); + + // Decrease test + payloads__.push_back(std::vector<std::shared_ptr<vsomeip::payload>>()); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07, 0x08, 0x09, 0x0A}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07, 0x08, 0x09}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07, 0x08}); + payloads__[debounce_test_id_e::DTI_DECREASE].push_back(its_payload); + + // Mask test + payloads__.push_back(std::vector<std::shared_ptr<vsomeip::payload>>()); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x10, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x20, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x22, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x23, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data({0x24, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07}); + payloads__[debounce_test_id_e::DTI_MASK].push_back(its_payload); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.hpp new file mode 100644 index 00000000000..14d12758868 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_client.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_CLIENT_HPP_ +#define DEBOUNCE_TEST_CLIENT_HPP_ + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_test_common.hpp" + +class debounce_test_client { +public: + debounce_test_client(debounce_test_id_e _test_id); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + +private: + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message>& _message); + + void run_test(); + void unsubscribe_all(); + void stop_service(); + + bool compare_payload(const std::shared_ptr<vsomeip::payload>& _payload, + std::size_t _index) const; + +private: + debounce_test_id_e test_id_; + size_t index_; + + bool is_available_; + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; +}; + +#endif // DEBOUNCE_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_common.hpp new file mode 100644 index 00000000000..b4c5df62b6f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_common.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_COMMON_HPP_ +#define DEBOUNCE_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t DEBOUNCE_SERVICE = 0xb657; +const vsomeip::instance_t DEBOUNCE_INSTANCE = 0x0003; +const vsomeip::method_t DEBOUNCE_START_METHOD = 0x0998; +const vsomeip::method_t DEBOUNCE_STOP_METHOD = 0x0999; +const vsomeip::event_t DEBOUNCE_EVENT = 0x8001; +const vsomeip::event_t DEBOUNCE_EVENT_2 = 0x8002; +const vsomeip::event_t DEBOUNCE_EVENT_4 = 0x8004; +const vsomeip::eventgroup_t DEBOUNCE_EVENTGROUP = 0x0005; +const vsomeip::major_version_t DEBOUNCE_MAJOR = 0x01; +const vsomeip::minor_version_t DEBOUNCE_MINOR = 0x01; + +enum debounce_test_id_e : uint8_t { + DTI_FLAT = 0x00, + DTI_INCREASE = 0x01, + DTI_DECREASE = 0x02, + DTI_MASK = 0x03 +}; + +#endif // DEBOUNCE_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.cpp new file mode 100644 index 00000000000..f9c2f4a3c29 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.cpp @@ -0,0 +1,262 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> + +#include "debounce_test_service.hpp" + +debounce_test_service::debounce_test_service(debounce_test_id_e _test_id) : + test_id_(_test_id), is_running_(true), runner_(std::bind(&debounce_test_service::run, this)), + app_(vsomeip::runtime::get()->create_application("debounce_test_service")) { } + +bool debounce_test_service::init() { + + bool is_initialized = app_->init(); + if (is_initialized) { + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_START_METHOD, + std::bind(&debounce_test_service::on_start, this, std::placeholders::_1)); + app_->register_message_handler( + DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_STOP_METHOD, + std::bind(&debounce_test_service::on_stop, this, std::placeholders::_1)); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_event(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, + {DEBOUNCE_EVENTGROUP}, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->offer_service(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_MAJOR, DEBOUNCE_MINOR); + } + return is_initialized; +} + +void debounce_test_service::start() { + + VSOMEIP_INFO << "Starting Service..."; + app_->start(); +} + +void debounce_test_service::stop() { + + VSOMEIP_INFO << "Stopping Service..."; + app_->stop(); +} + +void debounce_test_service::run() { + + { + std::unique_lock<std::mutex> its_lock(run_mutex_); + auto its_result = run_condition_.wait_for(its_lock, std::chrono::milliseconds(5000)); + if (its_result == std::cv_status::timeout) + return; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + start_test(); +} + +void debounce_test_service::wait() { + + if (runner_.joinable()) + runner_.join(); +} + +void debounce_test_service::on_start(const std::shared_ptr<vsomeip::message>& _message) { + + (void)_message; + + VSOMEIP_INFO << __func__ << ": Starting test " << std::dec << test_id_; + run_condition_.notify_one(); +} + +void debounce_test_service::on_stop(const std::shared_ptr<vsomeip::message>& _message) { + + (void)_message; + + VSOMEIP_INFO << __func__ << ": Received a STOP command."; + is_running_ = false; + stop(); +} + +void debounce_test_service::start_test() { + + if (test_id_ == debounce_test_id_e::DTI_FLAT) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x03, 0x02, 0x03, 0x04, 0x04, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x05, 0x02, 0x03, 0x04, 0x03, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x07, 0x02, 0x03, 0x04, 0x02, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + + its_payload->set_data({0x09, 0x02, 0x03, 0x04, 0x01, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT, its_payload); + } + + if (test_id_ == debounce_test_id_e::DTI_INCREASE) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + + its_payload->set_data({0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07, 0x08}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07, 0x08}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x03, 0x02, 0x03, 0x04, 0x04, 0x07, 0x07, 0x08, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07, 0x08, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x05, 0x02, 0x03, 0x04, 0x03, 0x07, 0x07, 0x08, 0x09, 0x0A}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07, 0x08, 0x09, 0x0A}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x07, 0x02, 0x03, 0x04, 0x02, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data( + {0x09, 0x02, 0x03, 0x04, 0x01, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + } + + if (test_id_ == debounce_test_id_e::DTI_DECREASE) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + + its_payload->set_data( + {0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x03, 0x02, 0x03, 0x04, 0x04, 0x07, 0x07, 0x08, 0x09, 0x0A}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x04, 0x02, 0x03, 0x04, 0x03, 0x06, 0x07, 0x08, 0x09, 0x0A}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x05, 0x02, 0x03, 0x04, 0x03, 0x07, 0x07, 0x08, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x06, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07, 0x08, 0x09}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x07, 0x02, 0x03, 0x04, 0x02, 0x07, 0x07, 0x08}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x08, 0x02, 0x03, 0x04, 0x01, 0x06, 0x07, 0x08}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + + its_payload->set_data({0x09, 0x02, 0x03, 0x04, 0x01, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_2, its_payload); + } + + if (test_id_ == debounce_test_id_e::DTI_MASK) { + auto its_payload = vsomeip::runtime::get()->create_payload(); + + its_payload->set_data({0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x10, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x12, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x20, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x21, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x22, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x23, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x24, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + + its_payload->set_data({0x25, 0x02, 0x03, 0x04, 0x05, 0x17, 0x07}); + app_->notify(DEBOUNCE_SERVICE, DEBOUNCE_INSTANCE, DEBOUNCE_EVENT_4, its_payload); + } +} + +TEST(debounce_test, flat) { + debounce_test_service its_service(debounce_test_id_e::DTI_FLAT); + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +TEST(debounce_test, increase) { + debounce_test_service its_service(debounce_test_id_e::DTI_INCREASE); + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +TEST(debounce_test, decrease) { + debounce_test_service its_service(debounce_test_id_e::DTI_DECREASE); + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +TEST(debounce_test, mask) { + debounce_test_service its_service(debounce_test_id_e::DTI_MASK); + ASSERT_TRUE(its_service.init()); + its_service.start(); + its_service.wait(); +} + +int main(int argc, char** argv) { + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.hpp new file mode 100644 index 00000000000..570e403bf40 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/debounce_tests/debounce_test_service.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef DEBOUNCE_TEST_SERVICE_HPP_ +#define DEBOUNCE_TEST_SERVICE_HPP_ + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "debounce_test_common.hpp" + +class debounce_test_service { +public: + debounce_test_service(debounce_test_id_e _test_id); + + bool init(); + void start(); + void stop(); + + void run(); + void wait(); + +private: + void on_start(const std::shared_ptr<vsomeip::message>& _message); + void on_stop(const std::shared_ptr<vsomeip::message>& _message); + + void start_test(); + + debounce_test_id_e test_id_; + + std::mutex run_mutex_; + std::condition_variable run_condition_; + + std::atomic<bool> is_running_; + std::thread runner_; + std::shared_ptr<vsomeip::application> app_; +}; + +#endif // DEBOUNCE_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/CMakeLists.txt new file mode 100644 index 00000000000..56fdc23bfee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/CMakeLists.txt @@ -0,0 +1,118 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(e2e_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + e2e_test_client_external.json + e2e_test_external_master_start.sh + e2e_test_external_slave_start.sh + e2e_test_service_external.json +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(e2e_test_client + e2e_test_client.cpp +) + +# Add test executable. +add_executable(e2e_test_service + e2e_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + e2e_test_client + e2e_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME e2e_test_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/e2e_test_external_master_start.sh e2e_test_client_external.json + TIMEOUT 180 +) + +if(TEST_E2E_PROFILE_04) + + # Configure necessary files into the build directory. + set(configuration_files + e2e_profile_04_test_client_external.json + e2e_profile_04_test_external_master_start.sh + e2e_profile_04_test_external_slave_start.sh + e2e_profile_04_test_service_external.json + ) + configure_files("${configuration_files}") + + # Add test executable. + add_executable(e2e_profile_04_test_client + e2e_profile_04_test_client.cpp + ) + + # Add test executable. + add_executable(e2e_profile_04_test_service + e2e_profile_04_test_service.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + e2e_profile_04_test_client + e2e_profile_04_test_service + ) + targets_link_default_libraries("${executables}") + targets_add_default_dependencies("${executables}") + + # Add custom test command. + add_custom_test( + NAME e2e_profile_04_test_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/e2e_profile_04_test_external_master_start.sh e2e_profile_04_test_client_external.json + TIMEOUT 180 + ) + +endif() + +if(TEST_E2E_PROFILE_07) + + # Configure necessary files into the build directory. + set(configuration_files + e2e_profile_07_test_client_external.json + e2e_profile_07_test_external_master_start.sh + e2e_profile_07_test_external_slave_start.sh + e2e_profile_07_test_service_external.json + ) + configure_files("${configuration_files}") + + # Add test executable. + add_executable(e2e_profile_07_test_client + e2e_profile_07_test_client.cpp + ) + + # Add test executable. + add_executable(e2e_profile_07_test_service + e2e_profile_07_test_service.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + e2e_profile_07_test_client + e2e_profile_07_test_service + ) + targets_link_default_libraries("${executables}") + targets_add_default_dependencies("${executables}") + + # Add custom test command. + add_custom_test( + NAME e2e_profile_07_test_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/e2e_profile_07_test_external_master_start.sh e2e_profile_07_test_client_external.json + TIMEOUT 180 + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_client_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_client_external.json.in new file mode 100644 index 00000000000..9fec0db05cf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_client_external.json.in @@ -0,0 +1,56 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1255" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0xd025", + "event_id" : "0x0001", + "profile" : "P04", + "variant" : "checker", + "crc_offset" : "64", + "data_id" : "0x2d" + }, + { + "service_id" : "0xd025", + "event_id" : "0x8001", + "profile" : "P04", + "variant" : "checker", + "crc_offset" : "64", + "data_id" : "0x2d" + } + ] + }, + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "1000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_master_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_master_start.sh.in new file mode 100755 index 00000000000..fcbfab104d1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_master_start.sh.in @@ -0,0 +1,71 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_profile_04_test_client_external.json" + exit 1 +fi + +MASTER_JSON_FILE=$1 +SERVICE_JSON_FILE=${MASTER_JSON_FILE/client/service} +ALLOW_DENY=$2 + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=client-sample +./e2e_profile_04_test_client --remote & +PID_CLIENT=$! + + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external e2e profile 04 test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/e2e_tests; ./e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** e2e_profile_04_test_service_external.json and +** e2e_profile_04_test_client_external.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for client_pid in "${PID_CLIENT}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_CLIENT + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_slave_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_slave_start.sh.in new file mode 100755 index 00000000000..17104b8214c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_external_slave_start.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_profile_04_test_service_external.json" + exit 1 +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=service-sample +./e2e_profile_04_test_service --remote & +PID_SERVICE=$! + +# Wait until client and service are finished +for client_pid in "${PID_SERVICE}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_SERVICE + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_service_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_service_external.json.in new file mode 100644 index 00000000000..5ef256d1d1b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_04_test_service_external.json.in @@ -0,0 +1,57 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277", + "has_session_handling" : "false" + } + ], + "services" : + [ + { + "service" : "0xd025", + "instance" : "0x0001", + "unreliable" : "30501" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0xd025", + "event_id" : "0x0001", + "profile" : "P04", + "variant" : "protector", + "crc_offset" : "64", + "data_id" : "0x2d" + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_client_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_client_external.json.in new file mode 100644 index 00000000000..d3a4b3cc76b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_client_external.json.in @@ -0,0 +1,56 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1255" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0xd025", + "event_id" : "0x0001", + "profile" : "P07", + "variant" : "checker", + "crc_offset" : "64", + "data_id" : "0x2d" + }, + { + "service_id" : "0xd025", + "event_id" : "0x8001", + "profile" : "P07", + "variant" : "checker", + "crc_offset" : "64", + "data_id" : "0x2d" + } + ] + }, + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "1000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_master_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_master_start.sh.in new file mode 100755 index 00000000000..d6455c1ea19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_master_start.sh.in @@ -0,0 +1,71 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_profile_07_test_client_external.json" + exit 1 +fi + +MASTER_JSON_FILE=$1 +SERVICE_JSON_FILE=${MASTER_JSON_FILE/client/service} +ALLOW_DENY=$2 + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=client-sample +./e2e_profile_07_test_client --remote & +PID_CLIENT=$! + + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external e2e profile 07 test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/e2e_tests; ./e2e_profile_07_test_external_slave_start.sh $SERVICE_JSON_FILE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./e2e_profile_07_test_external_slave_start.sh $SERVICE_JSON_FILE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** e2e_profile_07_test_external_slave_start.sh $SERVICE_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** e2e_profile_07_test_service_external.json and +** e2e_profile_07_test_client_external.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for client_pid in "${PID_CLIENT}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_CLIENT + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_slave_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_slave_start.sh.in new file mode 100755 index 00000000000..1b944ff3d96 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_external_slave_start.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_profile_07_test_service_external.json" + exit 1 +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=service-sample +./e2e_profile_07_test_service --remote & +PID_SERVICE=$! + +# Wait until client and service are finished +for client_pid in "${PID_SERVICE}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_SERVICE + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_service_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_service_external.json.in new file mode 100644 index 00000000000..4dc59f0c183 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_profile_07_test_service_external.json.in @@ -0,0 +1,57 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277", + "has_session_handling" : "false" + } + ], + "services" : + [ + { + "service" : "0xd025", + "instance" : "0x0001", + "unreliable" : "30501" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0xd025", + "event_id" : "0x0001", + "profile" : "P07", + "variant" : "protector", + "crc_offset" : "64", + "data_id" : "0x2d" + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_client_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_client_external.json.in new file mode 100644 index 00000000000..77bfa32a3d2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_client_external.json.in @@ -0,0 +1,83 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1255" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0x1234", + "event_id" : "0x8421", + "profile" : "CRC8", + "variant" : "checker", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + }, + { + "service_id" : "0x1234", + "event_id" : "0x8001", + "profile" : "CRC8", + "variant" : "checker", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + }, + { + "service_id" : "0x1234", + "event_id" : "0x6543", + "profile" : "CRC32", + "variant" : "checker", + "crc_offset" : "0" + }, + { + "service_id" : "0x1234", + "event_id" : "0x8002", + "profile" : "CRC32", + "variant" : "checker", + "crc_offset" : "0" + } + ] + }, + "routing" : "client-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_master_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_master_start.sh.in new file mode 100755 index 00000000000..5b4863b708b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_master_start.sh.in @@ -0,0 +1,71 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_test_client_external.json" + exit 1 +fi + +MASTER_JSON_FILE=$1 +SERVICE_JSON_FILE=${MASTER_JSON_FILE/client/service} +ALLOW_DENY=$2 + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=client-sample +./e2e_test_client --remote & +PID_CLIENT=$! + + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external e2e test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/e2e_tests; ./e2e_test_external_slave_start.sh $SERVICE_JSON_FILE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./e2e_test_external_slave_start.sh $SERVICE_JSON_FILE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** e2e_test_external_slave_start.sh $SERVICE_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** e2e_test_service_external.json and +** e2e_test_client_external.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for client_pid in "${PID_CLIENT}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_CLIENT + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_slave_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_slave_start.sh.in new file mode 100755 index 00000000000..a6855b157ce --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_external_slave_start.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script" + echo "For example: $0 e2e_test_service_external.json" + exit 1 +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=service-sample +./e2e_test_service --remote & +PID_SERVICE=$! + +# Wait until client and service are finished +for client_pid in "${PID_SERVICE}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_SERVICE + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_service_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_service_external.json.in new file mode 100644 index 00000000000..cb69f2b53ff --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/conf/e2e_test_service_external.json.in @@ -0,0 +1,66 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "e2e" : + { + "e2e_enabled" : "true", + "protected" : + [ + { + "service_id" : "0x1234", + "event_id" : "0x8001", + "profile" : "CRC8", + "variant" : "protector", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + }, + { + "service_id" : "0x1234", + "event_id" : "0x8002", + "profile" : "CRC32", + "variant" : "protector", + "crc_offset" : "0" + } + ] + }, + "routing" : "service-sample", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.cpp new file mode 100644 index 00000000000..f97f038ab4a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.cpp @@ -0,0 +1,315 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_profile_04_test_common.hpp" +#include "e2e_profile_04_test_client.hpp" + +#include <vsomeip/internal/logger.hpp> + +std::vector<std::vector<vsomeip::byte_t>> responses_; +std::vector<std::vector<vsomeip::byte_t>> events_; + +std::map<vsomeip::method_t, uint32_t> counters_; + + +e2e_profile_04_test_client::e2e_profile_04_test_client() + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&e2e_profile_04_test_client::run, this)), + received_(0) { + +} + +bool +e2e_profile_04_test_client::init() { + + if (!app_->init()) { + ADD_FAILURE() << __func__ << ": Cannot initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&e2e_profile_04_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + PROFILE_04_SERVICE, PROFILE_04_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&e2e_profile_04_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler( + PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + std::bind(&e2e_profile_04_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + return true; +} + +void +e2e_profile_04_test_client::start() { + + VSOMEIP_INFO << __func__ << ": Starting..."; + app_->start(); +} + +void +e2e_profile_04_test_client::stop() { + + VSOMEIP_INFO << __func__ << ": Stopping..."; + shutdown_service(); + app_->clear_all_handler(); + app_->stop(); +} + +void +e2e_profile_04_test_client::on_state(vsomeip::state_type_e _state) { + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE); + + // request event 0x8001, that is protected by E2E Profile 04 + app_->request_event(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_EVENT, { PROFILE_04_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + } +} + +void +e2e_profile_04_test_client::on_availability( + vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available) { + + VSOMEIP_INFO << __func__ << ": Client " + << std::hex << std::setw(4) << std::setfill('0') + << app_->get_client() + << " : Service [" << _service << "." << _instance + << "] is " << (_is_available ? "available." : "NOT available."); + + // check that correct service / instance ID gets available + if (_is_available) { + EXPECT_EQ(PROFILE_04_SERVICE, _service); + EXPECT_EQ(PROFILE_04_INSTANCE, _instance); + } + + if (PROFILE_04_SERVICE == _service && PROFILE_04_INSTANCE == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if (is_available_ && !_is_available) { + is_available_ = false; + } else if(_is_available && !is_available_) { + is_available_ = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + app_->subscribe(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_EVENTGROUP, PROFILE_04_MAJOR); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + condition_.notify_one(); + } + } +} + +void +e2e_profile_04_test_client::on_message(const std::shared_ptr<vsomeip::message> &_message) { + + VSOMEIP_INFO << __func__ << ": Received a message from Service [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "." << _message->get_instance() + << "] to Client/Session [" + << _message->get_client() << "/" << _message->get_session() + << "]"; + + EXPECT_EQ(PROFILE_04_SERVICE, _message->get_service()); + EXPECT_EQ(PROFILE_04_INSTANCE, _message->get_instance()); + + // check fixed payload / CRC in response for service: d025 method: 0001 + if (vsomeip::message_type_e::MT_RESPONSE == _message->get_message_type() + && PROFILE_04_METHOD == _message->get_method()) { + // check for calculated CRC status OK for the predefined fixed payload sent by service + VSOMEIP_INFO << "Method ID 0x0001 -> IS_VALID_CRC = " + << std::boolalpha << _message->is_valid_crc(); + EXPECT_EQ(true, _message->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID) + std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload(); + const auto its_data = its_payload->get_data(); + for (size_t i = 0; i < its_payload->get_length(); i++) + EXPECT_EQ(its_data[i], responses_[counters_[PROFILE_04_METHOD] + % PROFILE_O4_NUM_MESSAGES][i]); + + counters_[PROFILE_04_METHOD]++; + + } else if (vsomeip::message_type_e::MT_NOTIFICATION == _message->get_message_type() + && PROFILE_04_EVENT == _message->get_method()) { + + // check CRC / payload calculated by sender for event 0x8001 against expected payload + // check for calculated CRC status OK for the calculated CRC / payload sent by service + VSOMEIP_INFO << __func__ << ": Event 0x8001 -> IS_VALID_CRC = " + << std::boolalpha << _message->is_valid_crc(); + EXPECT_EQ(true, _message->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID nibble) + std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload(); + const auto its_data = its_payload->get_data(); + for (size_t i = 0; i< its_payload->get_length(); i++) + EXPECT_EQ(its_data[i], events_[counters_[PROFILE_04_EVENT] + % PROFILE_O4_NUM_MESSAGES][i]); + + counters_[PROFILE_04_EVENT]++; + } + + received_++; + if (received_ == PROFILE_O4_NUM_MESSAGES * 2) { + VSOMEIP_WARNING << __func__ << ": Client" + << std::setw(4) << std::setfill('0') << std::hex + << app_->get_client() + << " received all messages ~> going down!"; + } +} + +void +e2e_profile_04_test_client::run() { + + for (int i = 0; i < PROFILE_O4_NUM_MESSAGES; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_available_) { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(PROFILE_04_SERVICE); + request->set_instance(PROFILE_04_INSTANCE); + request->set_interface_version(PROFILE_04_MAJOR); + + // send a request which is not e2e protected and expect an + // protected answer holding a fixed payload (E2E Profile 04) + // this call triggers also an event 0x8001 which holds a + // calculated payload + request->set_method(PROFILE_04_METHOD); + + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + stop(); +} + +void +e2e_profile_04_test_client::join_sender_thread() { + + if (sender_.joinable()) { + sender_.join(); + } +} + +void +e2e_profile_04_test_client::shutdown_service() { + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(PROFILE_04_SERVICE); + request->set_instance(PROFILE_04_INSTANCE); + request->set_method(PROFILE_04_SHUTDOWN); + request->set_interface_version(PROFILE_04_MAJOR); + + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + // expect 10 responses + 10 events + EXPECT_EQ(received_, PROFILE_O4_NUM_MESSAGES * 2); +} + +TEST(someip_e2e_profile_04_test, test_crc_calculation) { + + e2e_profile_04_test_client test_client; + + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + + responses_ = { + { + 0x00, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2d, + 0xaa, 0x1d, 0x3f, 0xdf, 0x08, 0xb7, 0xf4, 0x4c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x01, 0x01, 0x00, 0x00, 0x2d, + 0xe7, 0xb7, 0x13, 0x87, 0x0c, 0x69, 0x02, 0x1c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x02, 0x01, 0x00, 0x00, 0x2d, + 0xb6, 0x19, 0x94, 0x2c, 0x10, 0x1b, 0x28, 0xae, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + events_ = { + { + 0x00, 0x50, 0x8f, 0x81, 0x01, 0x00, 0x00, 0x2d, + 0xed, 0x6e, 0x78, 0x8d, 0x08, 0xb7, 0xf4, 0x4c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0x00, 0x50, 0x8f, 0x82, 0x01, 0x00, 0x00, 0x2d, + 0x9d, 0xbb, 0x49, 0x3f, 0x0c, 0x69, 0x02, 0x1c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0x00, 0x50, 0x8f, 0x83, 0x01, 0x00, 0x00, 0x2d, + 0x13, 0x04, 0xf8, 0x81, 0x10, 0x1b, 0x28, 0xae, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.hpp new file mode 100644 index 00000000000..ad002913459 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_client.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_04_TEST_CLIENT_HPP_ +#define E2E_PROFILE_04_TEST_CLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <atomic> + +class e2e_profile_04_test_client { +public: + e2e_profile_04_test_client(); + + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic<uint32_t> received_; +}; + +#endif // E2E_PROFILE_04_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_common.hpp new file mode 100644 index 00000000000..04cba235787 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_common.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_04_TEST_COMMON_HPP_ +#define E2E_PROFILE_04_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t PROFILE_04_SERVICE = 0xd025; +const vsomeip::instance_t PROFILE_04_INSTANCE = 0x0001; +const vsomeip::major_version_t PROFILE_04_MAJOR = 0x01; +const vsomeip::minor_version_t PROFILE_04_MINOR = 0x00000000; + +const vsomeip::method_t PROFILE_04_METHOD = 0x0001; +const vsomeip::method_t PROFILE_04_SHUTDOWN = 0x0002; + +const vsomeip::eventgroup_t PROFILE_04_EVENTGROUP = 0x0001; +const vsomeip::event_t PROFILE_04_EVENT = 0x8001; + +#define PROFILE_O4_NUM_MESSAGES 3 + +#endif // E2E_PROFILE_04_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.cpp new file mode 100644 index 00000000000..acf34779b61 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.cpp @@ -0,0 +1,326 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_profile_04_test_common.hpp" +#include "e2e_profile_04_test_service.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; + +std::vector<std::vector<vsomeip::byte_t> > responses_; +std::vector<std::vector<vsomeip::byte_t> > events_; + +std::map<vsomeip::method_t, uint32_t> counters_; + +e2e_profile_04_test_service::e2e_profile_04_test_service() + : app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + offer_thread_(std::bind(&e2e_profile_04_test_service::run, this)), + received_(0) { +} + +bool +e2e_profile_04_test_service::init() { + + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << __func__ << ": Cannot initialize application."; + return false; + } + + app_->register_message_handler(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_METHOD, + std::bind(&e2e_profile_04_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_SHUTDOWN, + std::bind(&e2e_profile_04_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&e2e_profile_04_test_service::on_state, this, + std::placeholders::_1)); + + // E2E Profile 04: Event 8001 + app_->offer_event(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_EVENT, { PROFILE_04_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // Initialize the attribute + auto its_payload = vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[] = { + 0x00, 0x50, 0x8f, 0x80, 0x01, 0x00, 0x00, 0x2d, + 0xf3, 0x2a, 0x8c, 0x89, 0x05, 0x04, 0xcc, 0x46, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x40, 0xb1, 0x3e, 0xba, 0xc4, 0x76, 0x3f, 0xb3, + 0x7b, 0x03, 0xbd, 0x95, 0x74, 0x53, 0x3d, 0x32, + 0x4b, 0x9d, 0xbd, 0xbc, 0xd6, 0x3b, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1f, 0xf5, + 0xf6, 0x01, 0x01, 0x3c, 0x2b, 0xb1, 0xa2, 0x00 + }; + its_payload->set_data(its_data, sizeof(its_data)); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_payload); + + return true; +} + +void +e2e_profile_04_test_service::start() { + + VSOMEIP_INFO << __func__ << ": Starting..."; + app_->start(); +} + +void +e2e_profile_04_test_service::stop() { + + VSOMEIP_INFO << __func__ << ": Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void +e2e_profile_04_test_service::join_offer_thread() { + + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void +e2e_profile_04_test_service::offer() { + + app_->offer_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_MAJOR, PROFILE_04_MINOR); +} + +void +e2e_profile_04_test_service::stop_offer() { + + app_->stop_offer_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, + PROFILE_04_MAJOR, PROFILE_04_MINOR); +} + +void +e2e_profile_04_test_service::on_state(vsomeip::state_type_e _state) { + + VSOMEIP_INFO << __func__ << ": Application " + << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + + // "start" the run method thread + condition_.notify_one(); + } + } else { + is_registered_ = false; + } +} + +void +e2e_profile_04_test_service::on_message( + const std::shared_ptr<vsomeip::message> &_request) { + + ASSERT_EQ(PROFILE_04_SERVICE, _request->get_service()); + ASSERT_EQ(PROFILE_04_INSTANCE, _request->get_instance()); + + VSOMEIP_INFO << "Received a message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_client() << "/" << _request->get_session() + << "] method: " << _request->get_method() ; + + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + std::shared_ptr< vsomeip::payload > its_response_payload = + vsomeip::runtime::get()->create_payload(); + std::shared_ptr<vsomeip::payload> its_event_payload = + vsomeip::runtime::get()->create_payload(); + + // send fixed payload for profile 01 CRC8 + if (PROFILE_04_METHOD == _request->get_method()) { + its_response_payload->set_data(responses_[counters_[PROFILE_04_METHOD] % PROFILE_O4_NUM_MESSAGES]); + its_response->set_payload(its_response_payload); + app_->send(its_response); + + counters_[PROFILE_04_METHOD]++; + + // set value to field which gets filled by e2e protection with CRC on sending + its_event_payload->set_data(events_[counters_[PROFILE_04_EVENT] % PROFILE_O4_NUM_MESSAGES]); + app_->notify(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, PROFILE_04_EVENT, its_event_payload); + + counters_[PROFILE_04_EVENT]++; + } + + received_++; + if (received_ == PROFILE_O4_NUM_MESSAGES) { + VSOMEIP_INFO << __func__ << ": Received all messages!"; + } +} + +void +e2e_profile_04_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message> &_request) { + + (void)_request; + VSOMEIP_INFO << __func__ << ": Shutdown method was called, going down now."; + stop(); +} + +void +e2e_profile_04_test_service::run() { + + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_e2e_profile_04_test, basic_subscribe_request_response) { + e2e_profile_04_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + + counters_[PROFILE_04_METHOD] = 0; + counters_[PROFILE_04_EVENT] = 0; + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + // Payloads (without counter, data id and crc) + responses_ = { + { + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xb7, 0xf4, 0x4c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x69, 0x02, 0x1c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x1b, 0x28, 0xae, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + // Payloads (full data with counter, data id and crc to be sent raw) + events_ = { + { + 0x00, 0x50, 0x8f, 0x81, 0x01, 0x00, 0x00, 0x2d, + 0xed, 0x6e, 0x78, 0x8d, 0x08, 0xb7, 0xf4, 0x4c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0x00, 0x50, 0x8f, 0x82, 0x01, 0x00, 0x00, 0x2d, + 0x9d, 0xbb, 0x49, 0x3f, 0x0c, 0x69, 0x02, 0x1c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0x00, 0x50, 0x8f, 0x83, 0x01, 0x00, 0x00, 0x2d, + 0x13, 0x04, 0xf8, 0x81, 0x10, 0x1b, 0x28, 0xae, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.hpp new file mode 100644 index 00000000000..256179179a6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_04_test_service.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_04_TEST_SERVICE_HPP_ +#define E2E_PROFILE_04_TEST_SERVICE_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +class e2e_profile_04_test_service { +public: + e2e_profile_04_test_service(); + + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + bool blocked_; + std::mutex mutex_; + std::condition_variable condition_; + + std::thread offer_thread_; + + std::atomic<uint32_t> received_; +}; + +#endif // E2E_PROFILE_04_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.cpp new file mode 100644 index 00000000000..58faa3ec627 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.cpp @@ -0,0 +1,327 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_profile_07_test_common.hpp" +#include "e2e_profile_07_test_client.hpp" + +#include <vsomeip/internal/logger.hpp> + +std::vector<std::vector<vsomeip::byte_t>> responses_; +std::vector<std::vector<vsomeip::byte_t>> events_; + +std::map<vsomeip::method_t, uint32_t> counters_; + + +e2e_profile_07_test_client::e2e_profile_07_test_client() + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&e2e_profile_07_test_client::run, this)), + received_(0) { + +} + +bool +e2e_profile_07_test_client::init() { + + if (!app_->init()) { + ADD_FAILURE() << __func__ << ": Cannot initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&e2e_profile_07_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + PROFILE_07_SERVICE, PROFILE_07_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&e2e_profile_07_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler( + PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + std::bind(&e2e_profile_07_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + return true; +} + +void +e2e_profile_07_test_client::start() { + + VSOMEIP_INFO << __func__ << ": Starting..."; + app_->start(); +} + +void +e2e_profile_07_test_client::stop() { + + VSOMEIP_INFO << __func__ << ": Stopping..."; + shutdown_service(); + app_->clear_all_handler(); + app_->stop(); +} + +void +e2e_profile_07_test_client::on_state(vsomeip::state_type_e _state) { + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(PROFILE_07_SERVICE, PROFILE_07_INSTANCE); + + // request event 0x8001, that is protected by E2E Profile 07 + app_->request_event(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_EVENT, { PROFILE_07_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + } +} + +void +e2e_profile_07_test_client::on_availability( + vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available) { + + VSOMEIP_INFO << __func__ << ": Client " + << std::hex << std::setw(4) << std::setfill('0') + << app_->get_client() + << " : Service [" << _service << "." << _instance + << "] is " << (_is_available ? "available." : "NOT available."); + + // check that correct service / instance ID gets available + if (_is_available) { + EXPECT_EQ(PROFILE_07_SERVICE, _service); + EXPECT_EQ(PROFILE_07_INSTANCE, _instance); + } + + if (PROFILE_07_SERVICE == _service && PROFILE_07_INSTANCE == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if (is_available_ != !_is_available) { + is_available_ = false; + } else if(_is_available && !is_available_) { + is_available_ = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + app_->subscribe(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_EVENTGROUP, PROFILE_07_MAJOR); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + condition_.notify_one(); + } + } +} + +void +e2e_profile_07_test_client::on_message(const std::shared_ptr<vsomeip::message> &_message) { + + VSOMEIP_INFO << __func__ << ": Received a message from Service [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "." << _message->get_instance() + << "] to Client/Session [" + << _message->get_client() << "/" << _message->get_session() + << "]"; + + EXPECT_EQ(PROFILE_07_SERVICE, _message->get_service()); + EXPECT_EQ(PROFILE_07_INSTANCE, _message->get_instance()); + + // check fixed payload / CRC in response for service: d025 method: 0001 + if (vsomeip::message_type_e::MT_RESPONSE == _message->get_message_type() + && PROFILE_07_METHOD == _message->get_method()) { + // check for calculated CRC status OK for the predefined fixed payload sent by service + VSOMEIP_INFO << "Method ID 0x0001 -> IS_VALID_CRC = " + << std::boolalpha << _message->is_valid_crc(); + EXPECT_EQ(true, _message->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID) + std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload(); + const auto its_data = its_payload->get_data(); + for (size_t i = 0; i < its_payload->get_length(); i++) + EXPECT_EQ(its_data[i], responses_[counters_[PROFILE_07_METHOD] + % PROFILE_07_NUM_MESSAGES][i]); + + counters_[PROFILE_07_METHOD]++; + + } else if (vsomeip::message_type_e::MT_NOTIFICATION == _message->get_message_type() + && PROFILE_07_EVENT == _message->get_method()) { + + // check CRC / payload calculated by sender for event 0x8001 against expected payload + // check for calculated CRC status OK for the calculated CRC / payload sent by service + VSOMEIP_INFO << __func__ << ": Event 0x8001 -> IS_VALID_CRC = " + << std::boolalpha << _message->is_valid_crc(); + EXPECT_EQ(true, _message->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID nibble) + std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload(); + const auto its_data = its_payload->get_data(); + for (size_t i = 0; i< its_payload->get_length(); i++) + EXPECT_EQ(its_data[i], events_[counters_[PROFILE_07_EVENT] + % PROFILE_07_NUM_MESSAGES][i]); + + counters_[PROFILE_07_EVENT]++; + } + + received_++; + if (received_ == PROFILE_07_NUM_MESSAGES * 2) { + VSOMEIP_WARNING << __func__ << ": Client" + << std::setw(4) << std::setfill('0') << std::hex + << app_->get_client() + << " received all messages ~> going down!"; + } +} + +void +e2e_profile_07_test_client::run() { + + for (int i = 0; i < PROFILE_07_NUM_MESSAGES; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_available_) { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(PROFILE_07_SERVICE); + request->set_instance(PROFILE_07_INSTANCE); + request->set_interface_version(PROFILE_07_MAJOR); + + // send a request which is not e2e protected and expect an + // protected answer holding a fixed payload (E2E Profile 07) + // this call triggers also an event 0x8001 which holds a + // calculated payload + request->set_method(PROFILE_07_METHOD); + + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + stop(); +} + +void +e2e_profile_07_test_client::join_sender_thread() { + + if (sender_.joinable()) { + sender_.join(); + } +} + +void +e2e_profile_07_test_client::shutdown_service() { + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(PROFILE_07_SERVICE); + request->set_instance(PROFILE_07_INSTANCE); + request->set_method(PROFILE_07_SHUTDOWN); + request->set_interface_version(PROFILE_07_MAJOR); + + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + // expect 10 responses + 10 events + EXPECT_EQ(received_, PROFILE_07_NUM_MESSAGES * 2); +} + +TEST(someip_e2e_profile_07_test, test_crc_calculation) { + + e2e_profile_07_test_client test_client; + + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + + // The first 8 bytes are the CRC calculated over all the data (except the CRC itself) and the previous 8 bytes from the vSomeIP header + // The next 4 bytes are the length of the data + // The next 4 bytes are the counter, starting at 0 + // the next 4 bytes are the DataID + // The rest are just random for the test + // { + // CRC, + // Length, Counter, + // DataID, Random Data, + // Random Data + // } + + responses_ = { + { + 0xf7, 0xa1, 0x9e, 0x0e, 0x9d, 0xbd, 0xa7, 0xca, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0xca, 0xb7, 0xae, 0x78, 0xe2, 0xa5, 0xdc, 0xab, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0xbe, 0x5c, 0xe8, 0xd0, 0xa8, 0x3a, 0xca, 0x41, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + events_ = { + { + 0x23, 0xfc, 0x1f, 0x7f, 0x13, 0x58, 0x95, 0xc0, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0xd0, 0x18, 0xa8, 0x8d, 0x18, 0xcf, 0x43, 0x6e, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0xe1, 0x5d, 0x93, 0x59, 0x7e, 0x2a, 0xce, 0xc1, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.hpp new file mode 100644 index 00000000000..9b10a5891aa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_client.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_07_TEST_CLIENT_HPP_ +#define E2E_PROFILE_07_TEST_CLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <atomic> + +class e2e_profile_07_test_client { +public: + e2e_profile_07_test_client(); + + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic<uint32_t> received_; +}; + +#endif // E2E_PROFILE_07_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_common.hpp new file mode 100644 index 00000000000..07b9b7679af --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_common.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_07_TEST_COMMON_HPP_ +#define E2E_PROFILE_07_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +const vsomeip::service_t PROFILE_07_SERVICE = 0xd025; +const vsomeip::instance_t PROFILE_07_INSTANCE = 0x0001; +const vsomeip::major_version_t PROFILE_07_MAJOR = 0x01; +const vsomeip::minor_version_t PROFILE_07_MINOR = 0x00000000; + +const vsomeip::method_t PROFILE_07_METHOD = 0x0001; +const vsomeip::method_t PROFILE_07_SHUTDOWN = 0x0002; + +const vsomeip::eventgroup_t PROFILE_07_EVENTGROUP = 0x0001; +const vsomeip::event_t PROFILE_07_EVENT = 0x8001; + +#define PROFILE_07_NUM_MESSAGES 3 + +#endif // E2E_PROFILE_07_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.cpp new file mode 100644 index 00000000000..5e2a09293fc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.cpp @@ -0,0 +1,325 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_profile_07_test_common.hpp" +#include "e2e_profile_07_test_service.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; + +std::vector<std::vector<vsomeip::byte_t> > responses_; +std::vector<std::vector<vsomeip::byte_t> > events_; + +std::map<vsomeip::method_t, uint32_t> counters_; + +e2e_profile_07_test_service::e2e_profile_07_test_service() + : app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + offer_thread_(std::bind(&e2e_profile_07_test_service::run, this)), + received_(0) { +} + +bool +e2e_profile_07_test_service::init() { + + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << __func__ << ": Cannot initialize application."; + return false; + } + + app_->register_message_handler(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_METHOD, + std::bind(&e2e_profile_07_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_SHUTDOWN, + std::bind(&e2e_profile_07_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&e2e_profile_07_test_service::on_state, this, + std::placeholders::_1)); + + // E2E Profile 07: Event 8001 + app_->offer_event(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_EVENT, { PROFILE_07_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // Initialize the attribute + auto its_payload = vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[] = { + 0x00, 0x50, 0x8f, 0x80, 0x01, 0x00, 0x00, 0x2d, + 0xf3, 0x2a, 0x8c, 0x89, 0x05, 0x04, 0xcc, 0x46, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x40, 0xb1, 0x3e, 0xba, 0xc4, 0x76, 0x3f, 0xb3, + 0x7b, 0x03, 0xbd, 0x95, 0x74, 0x53, 0x3d, 0x32, + 0x4b, 0x9d, 0xbd, 0xbc, 0xd6, 0x3b, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1f, 0xf5, + 0xf6, 0x01, 0x01, 0x3c, 0x2b, 0xb1, 0xa2, 0x00 + }; + its_payload->set_data(its_data, sizeof(its_data)); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_payload); + + return true; +} + +void +e2e_profile_07_test_service::start() { + + VSOMEIP_INFO << __func__ << ": Starting..."; + app_->start(); +} + +void +e2e_profile_07_test_service::stop() { + + VSOMEIP_INFO << __func__ << ": Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void +e2e_profile_07_test_service::join_offer_thread() { + + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void +e2e_profile_07_test_service::offer() { + + app_->offer_service(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_MAJOR, PROFILE_07_MINOR); +} + +void +e2e_profile_07_test_service::stop_offer() { + + app_->stop_offer_service(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, + PROFILE_07_MAJOR, PROFILE_07_MINOR); +} + +void +e2e_profile_07_test_service::on_state(vsomeip::state_type_e _state) { + + VSOMEIP_INFO << __func__ << ": Application " + << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + + // "start" the run method thread + condition_.notify_one(); + } + } else { + is_registered_ = false; + } +} + +void +e2e_profile_07_test_service::on_message( + const std::shared_ptr<vsomeip::message> &_request) { + + ASSERT_EQ(PROFILE_07_SERVICE, _request->get_service()); + ASSERT_EQ(PROFILE_07_INSTANCE, _request->get_instance()); + + VSOMEIP_INFO << "Received a message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_client() << "/" << _request->get_session() + << "] method: " << _request->get_method() ; + + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + std::shared_ptr< vsomeip::payload > its_response_payload = + vsomeip::runtime::get()->create_payload(); + std::shared_ptr<vsomeip::payload> its_event_payload = + vsomeip::runtime::get()->create_payload(); + + // send fixed payload for profile 07 CRC64 + if (PROFILE_07_METHOD == _request->get_method()) { + its_response_payload->set_data(responses_[counters_[PROFILE_07_METHOD] % PROFILE_07_NUM_MESSAGES]); + its_response->set_payload(its_response_payload); + app_->send(its_response); + + counters_[PROFILE_07_METHOD]++; + + // set value to field which gets filled by e2e protection with CRC on sending + its_event_payload->set_data(events_[counters_[PROFILE_07_EVENT] % PROFILE_07_NUM_MESSAGES]); + app_->notify(PROFILE_07_SERVICE, PROFILE_07_INSTANCE, PROFILE_07_EVENT, its_event_payload); + + counters_[PROFILE_07_EVENT]++; + } + + received_++; + if (received_ == PROFILE_07_NUM_MESSAGES) { + VSOMEIP_INFO << __func__ << ": Received all messages!"; + } +} + +void +e2e_profile_07_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message> &_request) { + + (void)_request; + VSOMEIP_INFO << __func__ << ": Shutdown method was called, going down now."; + stop(); +} + +void +e2e_profile_07_test_service::run() { + + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_e2e_profile_07_test, basic_subscribe_request_response) { + e2e_profile_07_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + + counters_[PROFILE_07_METHOD] = 0; + counters_[PROFILE_07_EVENT] = 0; + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + // Payloads (without counter, data id and crc) + responses_ = { + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x69, 0x02, 0x1c, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x1b, 0x28, 0xae, + 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + events_ = { + { + 0x23, 0xfc, 0x1f, 0x7f, 0x13, 0x58, 0x95, 0xc0, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3, + 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25, + 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd, + 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00 + }, + { + 0xd0, 0x18, 0xa8, 0x8d, 0x18, 0xcf, 0x43, 0x6e, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3, + 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7, + 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89, + 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00 + }, + { + 0xe1, 0x5d, 0x93, 0x59, 0x7e, 0x2a, 0xce, 0xc1, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x06, 0xfe, + 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2, + 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3, + 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6, + 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80, + 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b, + 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00 + } + }; + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.hpp new file mode 100644 index 00000000000..ad6488a54d7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_profile_07_test_service.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_PROFILE_07_TEST_SERVICE_HPP_ +#define E2E_PROFILE_07_TEST_SERVICE_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +class e2e_profile_07_test_service { +public: + e2e_profile_07_test_service(); + + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + bool blocked_; + std::mutex mutex_; + std::condition_variable condition_; + + std::thread offer_thread_; + + std::atomic<uint32_t> received_; +}; + +#endif // E2E_PROFILE_07_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.cpp new file mode 100644 index 00000000000..9e270cca2ed --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.cpp @@ -0,0 +1,389 @@ +// Copyright (C) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_test_client.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; +std::vector<std::vector<vsomeip::byte_t>> payloads_profile_01_; +std::vector<std::vector<vsomeip::byte_t>> event_payloads_profile_01_; + +std::vector<std::vector<vsomeip::byte_t>> payloads_custom_profile_; +std::vector<std::vector<vsomeip::byte_t>> event_payloads_custom_profile_; + +std::map<vsomeip::method_t, uint32_t> received_responses_counters_; + + +e2e_test_client::e2e_test_client(bool _test_external_communication, + bool _is_remote_client_allowed) + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&e2e_test_client::run, this)), + received_responses_(0), + received_allowed_events_(0), + test_external_communication_(_test_external_communication), + is_remote_client_allowed_(_is_remote_client_allowed) { + +} + +bool e2e_test_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&e2e_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&e2e_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&e2e_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void e2e_test_client::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void e2e_test_client::stop() { + VSOMEIP_INFO << "Stopping..."; + shutdown_service(); + app_->clear_all_handler(); + app_->stop(); +} + +void e2e_test_client::on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request events of eventgroup 0x01 which holds events 0x8001 (CRC8) + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(0x01); + + // request events of eventgroup 0x02 which holds events 0x8002 (CRC32) + std::set<vsomeip::eventgroup_t> its_eventgroups_2; + its_eventgroups_2.insert(0x02); + + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), + its_eventgroups_2, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + } +} + +void e2e_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + // check that correct service / instance ID gets available + if (_is_available) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _service); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _instance); + } + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if(is_available_ && !_is_available) { + is_available_ = false; + } + else if(_is_available && !is_available_) { + is_available_ = true; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x01); + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x02); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + condition_.notify_one(); + } + } +} + +void e2e_test_client::on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance()); + + // check fixed payload / CRC in response for service: 1234 method: 8421 + if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE + && vsomeip_test::TEST_SERVICE_METHOD_ID == _response->get_method()) { + // check for calculated CRC status OK for the predefined fixed payload sent by service + VSOMEIP_INFO << "Method ID 0x8421 -> IS_VALID_CRC 8 = " << std::hex << _response->is_valid_crc(); + EXPECT_EQ(true, _response->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID nibble) + std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); + uint8_t* dataptr = pl->get_data(); //start after length field + for(uint32_t i = 0; i< pl->get_length(); i++) { + EXPECT_EQ(dataptr[i], payloads_profile_01_[received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]); + } + received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID]++; + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION + && 0x8001 == _response->get_method()) { + // check CRC / payload calculated by sender for event 0x8001 against expected payload + // check for calculated CRC status OK for the calculated CRC / payload sent by service + VSOMEIP_INFO << "Event ID 0x8001 -> IS_VALID_CRC 8 = " << std::hex << _response->is_valid_crc(); + EXPECT_EQ(true, _response->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID nibble) + std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); + uint8_t* dataptr = pl->get_data(); //start after length field + for(uint32_t i = 0; i< pl->get_length(); i++) { + EXPECT_EQ(dataptr[i], event_payloads_profile_01_[received_responses_counters_[0x8001] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]); + } + received_responses_counters_[0x8001]++; + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE + && 0x6543 == _response->get_method()) { + // check for calculated CRC status OK for the predefined fixed payload sent by service + VSOMEIP_INFO << "Method ID 0x6543 -> IS_VALID_CRC 32 = " << std::hex << _response->is_valid_crc(); + EXPECT_EQ(true, _response->is_valid_crc()); + + // check if payload is as expected as well (including CRC / counter / data ID nibble) + std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); + uint8_t* dataptr = pl->get_data(); //start after length field + for(uint32_t i = 0; i< pl->get_length(); i++) { + EXPECT_EQ(dataptr[i], payloads_custom_profile_[received_responses_counters_[0x6543] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]); + } + received_responses_counters_[0x6543]++; + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION + && 0x8002 == _response->get_method()) { + VSOMEIP_INFO << "Event ID 0x8002 -> IS_VALID_CRC 32 = " << std::hex << _response->is_valid_crc(); + EXPECT_EQ(true, _response->is_valid_crc()); + + // check if payload is as expected as well (including CRC) + std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); + uint8_t* dataptr = pl->get_data(); //start after length field + for(uint32_t i = 0; i< pl->get_length(); i++) { + EXPECT_EQ(dataptr[i], event_payloads_custom_profile_[received_responses_counters_[0x8002] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]); + } + received_responses_counters_[0x8002]++; + } + + received_responses_++; + if (received_responses_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND * 4) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + } +} + +void e2e_test_client::run() { + for (uint32_t i = 0; i < vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_available_) + { + condition_.wait(its_lock); + } + } + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + + // send a request which is not e2e protected and expect an + // protected answer holding a fixed payload (profile 01 CRC8) + // this call triggers also an event 0x8001 which holds a calculated payload + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + app_->send(request); + + // send a request which is not e2e protected and expect an + // protected answer holding a fixed payload (custom profile CRC32) + // this call triggers also an event 0x8002 which holds a calculated payload + request->set_method(0x6543); + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + stop(); +} + +void e2e_test_client::join_sender_thread() +{ + if (sender_.joinable()) { + sender_.join(); + } +} + +void e2e_test_client::shutdown_service() { + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + // expect 10 x response messages for both method IDs and events for both Event IDs + EXPECT_EQ(received_responses_, vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND * 4); + //EXPECT_EQ(received_allowed_events_, vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND); +} + +TEST(someip_e2e_test, basic_subscribe_request_response) +{ + e2e_test_client test_client(is_remote_test, remote_client_allowed); + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + + /* + e2e profile01 CRC8 protected fixed sample payloads sent by service + which must be received in client using the following config on client side: + "service_id" : "0x1234", + "event_id" : "0x8421", + "profile" : "CRC8", + "variant" : "checker", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + */ + payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); // initial event + payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + + /* + e2e profile01 CRC8 protected payloads which shall be created by e2e module on + service side using the following config on client side: + "service_id" : "0x1234", + "event_id" : "0x8001", + "profile" : "CRC8", + "variant" : "checker", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + */ + event_payloads_profile_01_.push_back({{0xa4, 0xa1, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}}); // initial event + event_payloads_profile_01_.push_back({{0x05, 0xa2, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0x92, 0xa3, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0x5a, 0xa4, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0xc8, 0xa5, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0x69, 0xa6, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0xfe, 0xa7, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0xe4, 0xa8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0x7c, 0xa9, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff}}); + event_payloads_profile_01_.push_back({{0xdd, 0xaa, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff}}); + + /* + e2e custom profile CRR32 protected fixed sample payloads sent by service + which must be received in client using the following config on client side: + "service_id" : "0x1234", + "event_id" : "0x6543", + "profile" : "CRC32", + "variant" : "checker", + "crc_offset" : "0" + */ + payloads_custom_profile_.push_back({{0xa4, 0xb2, 0x75, 0x1f, 0xff, 0x00, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa5, 0x70, 0x1f, 0x28, 0xff, 0x01, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa7, 0x36, 0xa1, 0x71, 0xff, 0x02, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa6, 0xf4, 0xcb, 0x46, 0xff, 0x03, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa3, 0xbb, 0xdd, 0xc3, 0xff, 0x04, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa2, 0x79, 0xb7, 0xf4, 0xff, 0x05, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa0, 0x3f, 0x09, 0xad, 0xff, 0x06, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa1, 0xfd, 0x63, 0x9a, 0xff, 0x07, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xaa, 0xa1, 0x24, 0xa7, 0xff, 0x08, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xab, 0x63, 0x4e, 0x90, 0xff, 0x09, 0xff, 0x32}}); + + /* + e2e custom profile CRC32 protected payloads which shall be created by e2e module on + service side using the following config on client side for checking: + "service_id" : "0x1234", + "event_id" : "0x8002", + "profile" : "CRC32", + "variant" : "checker", + "crc_offset" : "0" + */ + event_payloads_custom_profile_.push_back({{0x89, 0x0e, 0xbc, 0x80, 0xff, 0xff, 0x00, 0x32}}); + event_payloads_custom_profile_.push_back({{0x90, 0x15, 0x8d, 0xc1, 0xff, 0xff, 0x01, 0x32}}); + event_payloads_custom_profile_.push_back({{0xbb, 0x38, 0xde, 0x02, 0xff, 0xff, 0x02, 0x32}}); + event_payloads_custom_profile_.push_back({{0xa2, 0x23, 0xef, 0x43, 0xff, 0xff, 0x03, 0x32}}); + event_payloads_custom_profile_.push_back({{0xed, 0x62, 0x79, 0x84, 0xff, 0xff, 0x04, 0x32}}); + event_payloads_custom_profile_.push_back({{0xf4, 0x79, 0x48, 0xc5, 0xff, 0xff, 0x05, 0x32}}); + event_payloads_custom_profile_.push_back({{0xdf, 0x54, 0x1b, 0x06, 0xff, 0xff, 0x06, 0x32}}); + event_payloads_custom_profile_.push_back({{0xc6, 0x4f, 0x2a, 0x47, 0xff, 0xff, 0x07, 0x32}}); + event_payloads_custom_profile_.push_back({{0x41, 0xd7, 0x36, 0x88, 0xff, 0xff, 0x08, 0x32}}); + event_payloads_custom_profile_.push_back({{0x58, 0xcc, 0x07, 0xc9, 0xff, 0xff, 0x09, 0x32}}); + + received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] = 0; + received_responses_counters_[0x8001] = 0; + received_responses_counters_[0x6543] = 0; + received_responses_counters_[0x8002] = 0; + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.hpp new file mode 100644 index 00000000000..10f49784b0c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_client.hpp @@ -0,0 +1,56 @@ + +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef E2E_TEST_CLIENT_HPP +#define E2E_TEST_CLIENT_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <atomic> + +class e2e_test_client { +public: + e2e_test_client(bool _test_external_communication, + bool _is_remote_client_allowed); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> received_allowed_events_; + + bool test_external_communication_; + bool is_remote_client_allowed_; +}; + +#endif // E2E_TEST_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.cpp new file mode 100644 index 00000000000..16471670037 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.cpp @@ -0,0 +1,302 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "e2e_test_service.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; + +std::vector<std::vector<vsomeip::byte_t>> payloads_profile_01_; +std::vector<std::vector<vsomeip::byte_t>> payloads_custom_profile_; +std::map<vsomeip::method_t, uint32_t> received_requests_counters_; + +e2e_test_service::e2e_test_service() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&e2e_test_service::run, this)) { +} + +bool e2e_test_service::init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + // profile01 CRC8 Method ID: 0x8421 + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&e2e_test_service::on_message, this, + std::placeholders::_1)); + + // custom profile CRC32 Method ID: 0x6543 + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x6543, + std::bind(&e2e_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&e2e_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&e2e_test_service::on_state, this, + std::placeholders::_1)); + + // offer field 0x8001 eventgroup 0x01 + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(0x01); + + // offer field 0x8002 eventgroup 0x02 + std::set<vsomeip::eventgroup_t> its_eventgroups_2; + its_eventgroups_2.insert(0x02); + + // profile01 CRC8 Event ID: 0x8001 + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // set value to field which gets filled by e2e protection with CRC on sending + // after e2e protection the payload for first event should look like: + // {{0xa4, 0xa1, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff} + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[8] = {0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; + its_payload->set_data(its_data, 8); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_payload); + + // custom profile CRC32 Event ID: 0x8002 + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), its_eventgroups_2, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // set value to field which gets filled by e2e protection with CRC on sending + // after e2e protection the payload for first event should look like: + // {{0x89, 0x0e, 0xbc, 0x80, 0xff, 0xff, 0x00, 0x32} + std::shared_ptr<vsomeip::payload> its_payload_8002 = + vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data_8002[8] = {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x32}; + its_payload_8002->set_data(its_data_8002, 8); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), its_payload_8002); + + return true; +} + +void e2e_test_service::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void e2e_test_service::stop() { + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void e2e_test_service::join_offer_thread() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void e2e_test_service::offer() { + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void e2e_test_service::stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void e2e_test_service::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + if(!is_registered_) { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else { + is_registered_ = false; + } +} + +void e2e_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) { + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _request->get_instance()); + + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "] method: " << _request->get_method() ; + + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + std::shared_ptr< vsomeip::payload > its_vsomeip_payload = + vsomeip::runtime::get()->create_payload(); + std::shared_ptr<vsomeip::payload> its_event_payload = + vsomeip::runtime::get()->create_payload(); + + // send fixed payload for profile 01 CRC8 + if (_request->get_method() == vsomeip_test::TEST_SERVICE_METHOD_ID) { + its_vsomeip_payload->set_data(payloads_profile_01_[received_requests_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND]); + its_response->set_payload(its_vsomeip_payload); + app_->send(its_response); + + // set value to field which gets filled by e2e protection with CRC on sending + vsomeip::byte_t its_data[8] = {0x00, 0x00, (uint8_t)received_requests_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID], 0xff, 0xff, 0xff, 0xff, 0xff}; + its_event_payload->set_data(its_data, 8); + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_event_payload); + received_requests_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID]++; + } else if (_request->get_method() == 0x6543) { + //send fixed payload for custom profile CRC32 + its_vsomeip_payload->set_data(payloads_custom_profile_[received_requests_counters_[0x6543] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND]); + its_response->set_payload(its_vsomeip_payload); + app_->send(its_response); + + // set value to field which gets filled by e2e protection with 4 byte CRC 32 on sending + vsomeip::byte_t its_data[8] = {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, (uint8_t)received_requests_counters_[0x6543], 0x32}; + its_event_payload->set_data(its_data, 8); + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), its_event_payload); + received_requests_counters_[0x6543]++; + } + + number_of_received_messages_++; + if(number_of_received_messages_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND * 2) { + VSOMEIP_INFO << "Received all messages!"; + } +} + +void e2e_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + stop(); +} + +void e2e_test_service::run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + offer(); +} + +TEST(someip_e2e_test, basic_subscribe_request_response) { + e2e_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + /* + e2e profile01 CRC8 protected sample payloads using the following config at receiver: + "service_id" : "0x1234", + "event_id" : "0x8421", + "profile" : "CRC8", + "variant" : "checker", + "crc_offset" : "0", + "data_id_mode" : "3", + "data_length" : "56", + "data_id" : "0xA73" + */ + payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}}); + + /* + e2e custom profile CRC32 protected sample payloads using the following config at receiver: + "service_id" : "0x1234", + "event_id" : "0x6543", + "profile" : "CRC32", + "variant" : "checker", + "crc_offset" : "0" + */ + payloads_custom_profile_.push_back({{0xa4, 0xb2, 0x75, 0x1f, 0xff, 0x00, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa5, 0x70, 0x1f, 0x28, 0xff, 0x01, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa7, 0x36, 0xa1, 0x71, 0xff, 0x02, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa6, 0xf4, 0xcb, 0x46, 0xff, 0x03, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa3, 0xbb, 0xdd, 0xc3, 0xff, 0x04, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa2, 0x79, 0xb7, 0xf4, 0xff, 0x05, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa0, 0x3f, 0x09, 0xad, 0xff, 0x06, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xa1, 0xfd, 0x63, 0x9a, 0xff, 0x07, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xaa, 0xa1, 0x24, 0xa7, 0xff, 0x08, 0xff, 0x32}}); + payloads_custom_profile_.push_back({{0xab, 0x63, 0x4e, 0x90, 0xff, 0x09, 0xff, 0x32}}); + + received_requests_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] = 0; + received_requests_counters_[0x7654] = 0; + received_requests_counters_[0x6543] = 0; + received_requests_counters_[0x5432] = 0; + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.hpp new file mode 100644 index 00000000000..7fd1c5a9ec5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/e2e_tests/e2e_test_service.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef e2e_test_SERVICE_HPP +#define e2e_test_SERVICE_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> + +class e2e_test_service { +public: + e2e_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; +}; + +#endif // E2E_TEST_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/CMakeLists.txt new file mode 100644 index 00000000000..54bde4d6197 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(event_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + event_test_master.json + event_test_master_starter.sh + event_test_slave_starter.sh + event_test_slave_tcp.json + event_test_slave_udp.json +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(event_test_client + event_test_client.cpp +) + +# Add test executable. +add_executable(event_test_service + event_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + event_test_client + event_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME event_test_payload_fixed_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/event_test_master_starter.sh PAYLOAD_FIXED UDP + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME event_test_payload_fixed_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/event_test_master_starter.sh PAYLOAD_FIXED TCP + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME event_test_payload_dynamic_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/event_test_master_starter.sh PAYLOAD_DYNAMIC UDP + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME event_test_payload_dynamic_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/event_test_master_starter.sh PAYLOAD_DYNAMIC TCP + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master.json.in new file mode 100644 index 00000000000..effa3e9a305 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master.json.in @@ -0,0 +1,32 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "event_test_client", + "id" : "0x3489", + "max_dispatch_time" : "1000" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master_starter.sh.in new file mode 100755 index 00000000000..74a25ae8756 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_master_starter.sh.in @@ -0,0 +1,61 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +if [ $# -lt 2 ] +then + echo "Please pass a operation and communication mode to this script." + echo "For example: $0 PAYLOAD_FIXED UDP" + echo "Valid operation modes include [PAYLOAD_FIXED, PAYLOAD_DYNAMIC]" + echo "Valid communication modes include [UDP, TCP]" + exit 1 +fi +TESTMODE=$1 +COMMUNICATIONMODE=$2 + +export VSOMEIP_CONFIGURATION=event_test_master.json +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +./event_test_client $TESTMODE $COMMUNICATIONMODE & +PID_CLIENT=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/event_tests; ./event_test_slave_starter.sh $COMMUNICATIONMODE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && sleep 10; ./event_test_slave_starter.sh $COMMUNICATIONMODE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** event_test_slave_starter.sh $COMMUNICATIONMODE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** event_test_slave_{udp,tcp}.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +for job in $PID_CLIENT +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_starter.sh.in new file mode 100755 index 00000000000..a7871dbda2c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_starter.sh.in @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +if [ $# -lt 1 ] +then + echo "Please pass a operation and communication mode to this script." + echo "For example: $0 UDP" + echo "Valid communication modes include [UDP, TCP]" + exit 1 +fi +COMMUNICATIONMODE=$1 + +if [ "$COMMUNICATIONMODE" = "TCP" ]; then + export VSOMEIP_CONFIGURATION=event_test_slave_tcp.json +elif [ "$COMMUNICATIONMODE" = "UDP" ]; then + export VSOMEIP_CONFIGURATION=event_test_slave_udp.json +fi + +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +./event_test_service $COMMUNICATIONMODE & +PID_SERVICE=$! + +# Wait until all clients and services are finished +for job in $PID_SERVICE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_tcp.json.in new file mode 100644 index 00000000000..a0c97c61e04 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_tcp.json.in @@ -0,0 +1,43 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "event_test_service", + "id" : "0x1210", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3344", + "instance":"0x0001", + "reliable": { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_udp.json.in new file mode 100644 index 00000000000..c0610680c17 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/conf/event_test_slave_udp.json.in @@ -0,0 +1,40 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "event_test_service", + "id" : "0x1210", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3344", + "instance":"0x0001", + "unreliable":"30001" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_client.cpp new file mode 100644 index 00000000000..9feb686841f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_client.cpp @@ -0,0 +1,287 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "event_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class event_test_client : public vsomeip_utilities::base_logger { +public: + event_test_client(struct event_test::service_info _service_info, event_test::test_mode_e _mode, + bool _use_tcp) : + vsomeip_utilities::base_logger("EVTC", "EVENT TEST CLIENT"), + service_info_(_service_info), + test_mode_(_mode), + use_tcp_(_use_tcp), + app_(vsomeip::runtime::get()->create_application("event_test_client")), + service_available_(false), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_until_subscription_accepted_(true), + wait_until_events_received_(true), + wait_until_shutdown_reply_received_(true), + number_events_to_send_(50), + number_events_received_(0), + send_thread_(std::bind(&event_test_client::send, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&event_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&event_test_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&event_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(service_info_.service_id, + service_info_.instance_id); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->request_event(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + its_eventgroups, vsomeip::event_type_e::ET_EVENT, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->register_subscription_status_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + service_info_.event_id, + std::bind(&event_test_client::on_subscription_status_changed, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5)); + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.eventgroup_id); + + app_->start(); + } + + ~event_test_client() { + send_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + if (_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_service_available_ = false; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + on_notification(_message); + } else if (_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + on_response(_message); + } + } + + void on_notification(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.event_id, _message->get_method()); + if (test_mode_ == event_test::test_mode_e::PAYLOAD_FIXED) { + EXPECT_EQ(event_test::payload_fixed_length, _message->get_payload()->get_length()); + } else if (test_mode_ == event_test::test_mode_e::PAYLOAD_DYNAMIC) { + static vsomeip::length_t length_last_received_msg(0); + EXPECT_GT(_message->get_payload()->get_length(), length_last_received_msg); + length_last_received_msg = _message->get_payload()->get_length(); + + } + if (++number_events_received_ == number_events_to_send_) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_events_received_ = false; + condition_.notify_one(); + } + + VSOMEIP_DEBUG + << "Received a notification with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "]"; + + } + + void on_response(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.shutdown_method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_reply_received_ = false; + condition_.notify_one(); + } + + void on_subscription_status_changed(const vsomeip::service_t _service, + const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, + const vsomeip::event_t _event, + const uint16_t error_code) { + EXPECT_EQ(service_info_.service_id, _service); + EXPECT_EQ(service_info_.instance_id, _instance); + EXPECT_EQ(service_info_.eventgroup_id, _eventgroup); + EXPECT_EQ(service_info_.event_id, _event); + EXPECT_TRUE((error_code == 0x0u || error_code == 0x7u)); + if (error_code == 0x0u) { // accepted + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_subscription_accepted_ = false; + condition_.notify_one(); + } + } + + void send() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + while (wait_until_service_available_) { + condition_.wait(its_lock); + } + + while (wait_until_subscription_accepted_) { + if (std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(30))) { + VSOMEIP_ERROR << "Subscription wasn't accepted in time!"; + break; + } + } + + // call notify method + auto its_message = vsomeip::runtime::get()->create_request(use_tcp_); + its_message->set_service(service_info_.service_id); + its_message->set_instance(service_info_.instance_id); + its_message->set_method(service_info_.notify_method_id); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(std::vector<vsomeip::byte_t>({ + static_cast<vsomeip::byte_t>(test_mode_), + static_cast<vsomeip::byte_t>(number_events_to_send_)})); + its_message->set_payload(its_payload); + app_->send(its_message); + + while (wait_until_events_received_) { + if (std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(30))) { + VSOMEIP_ERROR << "Didn't receive events in time!"; + break; + } + } + + // shutdown service + its_message->set_method(service_info_.shutdown_method_id); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST); + app_->send(its_message); + + while (wait_until_shutdown_reply_received_) { + if (std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(30))) { + VSOMEIP_ERROR << "Shutdown request wasn't answered in time!"; + break; + } + } + } + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + + +private: + struct event_test::service_info service_info_; + event_test::test_mode_e test_mode_; + bool use_tcp_; + std::shared_ptr<vsomeip::application> app_; + bool service_available_; + + bool wait_until_registered_; + bool wait_until_service_available_; + bool wait_until_subscription_accepted_; + bool wait_until_events_received_; + bool wait_until_shutdown_reply_received_; + std::mutex mutex_; + std::condition_variable condition_; + + const std::uint8_t number_events_to_send_; + std::atomic<std::uint32_t> number_events_received_; + std::thread send_thread_; +}; + +static event_test::test_mode_e passed_mode = event_test::test_mode_e::PAYLOAD_FIXED; +static bool use_tcp = false; + +TEST(someip_event_test, subscribe_or_call_method_at_service) +{ + event_test_client its_sample(event_test::service, passed_mode, use_tcp); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 3) { + std::cerr << "Please specify a operation mode, like: " << argv[0] << "PAYLOAD_FIXED TCP" << std::endl; + std::cerr << "Valid operation modes are PAYLOAD_FIXED and PAYLOAD_DYNAMIC" << std::endl; + std::cerr << "Valid communication modes are UDP or TCP" << std::endl; + return 1; + } + + if (std::string("PAYLOAD_FIXED") == std::string(argv[1])) { + passed_mode = event_test::test_mode_e::PAYLOAD_FIXED; + } else if (std::string("PAYLOAD_DYNAMIC") == std::string(argv[1])) { + passed_mode = event_test::test_mode_e::PAYLOAD_DYNAMIC; + } else { + std::cerr << "Wrong operation mode passed, exiting" << std::endl; + std::cerr << "Please specify a operation mode, like: " << argv[0] << " PAYLOAD_FIXED" << std::endl; + std::cerr << "Valid operation modes are PAYLOAD_FIXED and PAYLOAD_DYNAMIC" << std::endl; + return 1; + } + if (std::string("TCP")== std::string(argv[2])) { + use_tcp = true; + } else if (std::string("UDP")== std::string(argv[2])) { + use_tcp = false; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_globals.hpp new file mode 100644 index 00000000000..733c3c66554 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_globals.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EVENT_TEST_GLOBALS_HPP_ +#define EVENT_TEST_GLOBALS_HPP_ + +namespace event_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::method_t notify_method_id; +}; + +struct service_info service = { 0x3344, 0x1, 0x1111, 0x8002, 0x1, 0x1404, 0x4242 }; + +enum test_mode_e : std::uint8_t { + UNKNOWN, + PAYLOAD_FIXED, + PAYLOAD_DYNAMIC +}; + +std::uint32_t payload_fixed_length = 20; + +} + +#endif /* EVENT_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_service.cpp new file mode 100644 index 00000000000..5f7099ffb5e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/event_tests/event_test_service.cpp @@ -0,0 +1,205 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <map> +#include <sstream> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "event_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class event_test_service : public vsomeip_utilities::base_logger { +public: + event_test_service(struct event_test::service_info _service_info, bool _use_tcp) : + vsomeip_utilities::base_logger("EVTS", "EVENT TEST SERVICE"), + service_info_(_service_info), + test_mode_(event_test::test_mode_e::UNKNOWN), + app_(vsomeip::runtime::get()->create_application("event_test_service")), + wait_until_registered_(true), + wait_until_notify_method_called_(true), + wait_until_shutdown_method_called_(true), + client_subscribed_(false), + notifications_to_send_(0), + offer_thread_(std::bind(&event_test_service::run, this)), + use_tcp_(_use_tcp) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&event_test_service::on_state, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(_service_info.eventgroup_id); + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&event_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.notify_method_id, + std::bind(&event_test_service::on_message, this, + std::placeholders::_1)); + app_->register_subscription_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + std::bind(&event_test_service::subscription_handler, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + + app_->start(); + } + + ~event_test_service() { + offer_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + } + + void stop() { + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.notify_method_id, _message->get_method()); + auto its_payload = _message->get_payload(); + ASSERT_EQ(2u, its_payload->get_length()); + test_mode_ = static_cast<event_test::test_mode_e>(its_payload->get_data()[0]); + notifications_to_send_ = static_cast<std::uint32_t>(its_payload->get_data()[1]); + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_notify_method_called_ = false; + condition_.notify_one(); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_until_notify_method_called_) { + condition_.wait(its_lock); + } + VSOMEIP_INFO << "notify"; + notify(); + + + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + its_lock.unlock(); + stop(); + } + + void notify() { + EXPECT_TRUE(client_subscribed_); + auto its_payload = vsomeip::runtime::get()->create_payload(); + for (std::uint32_t i = 0; i < notifications_to_send_; i++) { + if (test_mode_ == event_test::test_mode_e::PAYLOAD_FIXED) { + its_payload->set_data(std::vector<vsomeip::byte_t>(event_test::payload_fixed_length, 0x44)); + } else if (test_mode_ == event_test::test_mode_e::PAYLOAD_DYNAMIC) { + its_payload->set_data(std::vector<vsomeip::byte_t>(i+1, 0x55)); + } + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload, false); + } + } + + bool subscription_handler(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) { + (void)_uid; + (void)_gid; + VSOMEIP_INFO << __func__ << ": client: 0x" << std::hex << _client + << ((_subscribed) ? " subscribed" : "unsubscribed"); + client_subscribed_ = _subscribed; + return true; + } + +private: + struct event_test::service_info service_info_; + event_test::test_mode_e test_mode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_notify_method_called_; + bool wait_until_shutdown_method_called_; + std::atomic<bool> client_subscribed_; + std::uint32_t notifications_to_send_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + bool use_tcp_; +}; + +static bool use_tcp = false; + +TEST(someip_event_test, send_events) +{ + event_test_service its_sample(event_test::service, use_tcp); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + + if (std::string("TCP")== std::string(argv[1])) { + use_tcp = true; + } else if (std::string("UDP")== std::string(argv[1])) { + use_tcp = false; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/CMakeLists.txt new file mode 100644 index 00000000000..ac81f1ae955 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(header_factory_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + header_factory_test_client.json + header_factory_test_client_start.sh + header_factory_test_send_receive_starter.sh + header_factory_test_service.json + header_factory_test_service_start.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(header_factory_test + header_factory_test.cpp +) + +# Add test executable. +add_executable(header_factory_test_client + header_factory_test_client.cpp +) + +# Add test executable. +add_executable(header_factory_test_service + header_factory_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + header_factory_test + header_factory_test_client + header_factory_test_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Link thread libraries to executables. +foreach(target ${executables}) + target_link_libraries(${target} + ${CMAKE_THREAD_LIBS_INIT} + ) +endforeach() + +# Add custom test command. +add_custom_test( + NAME header_factory_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/header_factory_test +) + +# Add custom test command. +add_custom_test( + NAME header_factory_test_send_receive + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/header_factory_test_send_receive_starter.sh +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client.json.in new file mode 100644 index 00000000000..601cd553528 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client.json.in @@ -0,0 +1,97 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "header_factory_test_client", + "id" : "0x1343" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true" + }, + + { + "event" : "0x0778", + "is_field" : "false" + }, + + { + "event" : "0x0779", + "is_field" : "true" + } + ], + + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : + [ + "0x777", + "0x778" + ] + }, + + { + "eventgroup" : "0x4465", + "events" : + [ + "0x778", + "0x779" + ], + + "is_multicast" : "true" + }, + + { + "eventgroup" : "0x4555", + "events" : + [ + "0x777", + "0x779" + ] + } + ] + } + ], + + "routing" : "header_factory_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client_start.sh.in new file mode 100755 index 00000000000..9fa50826cef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_client_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=header_factory_test_client +export VSOMEIP_CONFIGURATION=header_factory_test_client.json +./header_factory_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_send_receive_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_send_receive_starter.sh.in new file mode 100755 index 00000000000..c9ce0ea06ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_send_receive_starter.sh.in @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Start the service +export VSOMEIP_APPLICATION_NAME=header_factory_test_service +export VSOMEIP_CONFIGURATION=header_factory_test_service.json +./header_factory_test_service & +sleep 1 + +# Start the client +export VSOMEIP_APPLICATION_NAME=header_factory_test_client +export VSOMEIP_CONFIGURATION=header_factory_test_client.json +if ! ./header_factory_test_client +then + FAIL=$((FAIL+1)) +fi + +# Wait until service is finished +# Fail gets incremented if service exit +# with a non-zero exit code +wait $! || FAIL=$((FAIL+1)) + +# Check if client and server both exited sucessfully +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service.json.in new file mode 100644 index 00000000000..f011629ab49 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service.json.in @@ -0,0 +1,105 @@ +{ + "unicast" : "127.0.0.1", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "header_factory_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + }, + + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true", + "update-cycle" : 2000 + }, + + { + "event" : "0x0778", + "is_field" : "true", + "update-cycle" : 0 + }, + + { + "event" : "0x0779", + "is_field" : "true" + } + ], + + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : + [ + "0x777", + "0x778" + ] + }, + + { + "eventgroup" : "0x4465", + "events" : + [ + "0x778", + "0x779" + ], + + "is_multicast" : "true" + }, + + { + "eventgroup" : "0x4555", + "events" : + [ + "0x777", + "0x779" + ] + } + ] + } + ], + + "routing" : "header_factory_test_service", + + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service_start.sh.in new file mode 100755 index 00000000000..e123a46fb12 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/conf/header_factory_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=header_factory_test_service +export VSOMEIP_CONFIGURATION=header_factory_test_service.json +./header_factory_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test.cpp new file mode 100644 index 00000000000..fd780ffe32a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class someip_header_factory_test: public ::testing::Test +{ +protected: + std::shared_ptr<vsomeip::message> request_; + std::shared_ptr<vsomeip::message> response_; + std::shared_ptr<vsomeip::message> notification_; + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> message_; + + vsomeip::service_t service_id_ = vsomeip_test::TEST_SERVICE_SERVICE_ID; + vsomeip::method_t method_id_ = vsomeip_test::TEST_SERVICE_METHOD_ID; + vsomeip::instance_t instance_id_ = vsomeip_test::TEST_SERVICE_INSTANCE_ID; + vsomeip::interface_version_t interface_version_ = 0x01; + vsomeip::client_t client_id_ = vsomeip_test::TEST_CLIENT_CLIENT_ID; + vsomeip::session_t session_id_ = vsomeip_test::TEST_INITIAL_SESSION_ID; +}; + +TEST_F(someip_header_factory_test, create_request_test) +{ + ASSERT_TRUE(request_.get() == nullptr); + request_ = vsomeip::runtime::get()->create_request(); + + // check that returned shared_ptr is not null + ASSERT_TRUE(request_.get() != nullptr); + + // Check the protocol version + // this shall be set to 0x01 according to the spec. TR_SOMEIP_00052 + ASSERT_EQ(request_->get_protocol_version(), 0x01); + // Check the message type + // this shall be 0x00 (REQUEST) according to the spec. TR_SOMEIP_00055 + ASSERT_EQ(request_->get_message_type(), vsomeip::message_type_e::MT_REQUEST); + // Check the return code + // this shall be 0x00 (E_OK) according to the spec. TR_SOMEIP_00058 + ASSERT_EQ(request_->get_return_code(), vsomeip::return_code_e::E_OK); + +} + +TEST_F(someip_header_factory_test, create_request_and_response_test) +{ + ASSERT_TRUE(request_.get() == nullptr); + request_ = vsomeip::runtime::get()->create_request(); + // check that returned shared_ptr is not null + ASSERT_TRUE(request_.get() != nullptr); + + request_->set_service(service_id_); + request_->set_method(method_id_); + request_->set_interface_version(interface_version_); + // set the request_id (client_id + session_id). This normally is set by the + // application_impl::send() if a request is send, we set it here to test the + // correct initialization of the response + request_->set_client(client_id_); + request_->set_session(session_id_); + + ASSERT_TRUE(response_.get() == nullptr); + response_ = vsomeip::runtime::get()->create_response(request_); + // check that returned shared_ptr is not null + ASSERT_TRUE(response_.get() != nullptr); + + ASSERT_EQ(response_->get_service(), request_->get_service()); + ASSERT_EQ(response_->get_method(), request_->get_method()); + ASSERT_EQ(response_->get_session(), request_->get_session()); + + // length? --> gets only set if a payload is added + + ASSERT_EQ(response_->get_protocol_version(), request_->get_protocol_version()); + ASSERT_EQ(response_->get_interface_version(), request_->get_interface_version()); + + // Check the message type + // this shall be 0x00 (REQUEST) according to the spec. TR_SOMEIP_00055 + ASSERT_EQ(request_->get_message_type(), vsomeip::message_type_e::MT_REQUEST); + + // Check the message type + // this shall be 0x80 (RESPONSE) according to the spec. TR_SOMEIP_00055 + ASSERT_EQ(response_->get_message_type(), vsomeip::message_type_e::MT_RESPONSE); + + // Check the return code + // this shall be 0x00 (E_OK) according to the spec. TR_SOMEIP_00058 + // and TR_SOMEIP_00191 + ASSERT_EQ(response_->get_return_code(), vsomeip::return_code_e::E_OK); + +} + +TEST_F(someip_header_factory_test, create_notification_test) +{ + ASSERT_TRUE(notification_.get() == nullptr); + notification_ = vsomeip::runtime::get()->create_notification(); + + // check that returned shared_ptr is not null + ASSERT_TRUE(notification_.get() != nullptr); + + // Check the protocol version + // this shall be set to 0x01 according to the spec. TR_SOMEIP_00052 + ASSERT_EQ(notification_->get_protocol_version(), 0x01); + // Check the message type + // this shall be 0x02 (NOTIFICATION) according to the spec. TR_SOMEIP_00055 + ASSERT_EQ(notification_->get_message_type(), vsomeip::message_type_e::MT_NOTIFICATION); + // Check the return code + // this shall be 0x00 (E_OK) according to the spec. TR_SOMEIP_00058 + ASSERT_EQ(notification_->get_return_code(), vsomeip::return_code_e::E_OK); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.cpp new file mode 100644 index 00000000000..59395ee66fc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.cpp @@ -0,0 +1,172 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "header_factory_test_client.hpp" + +header_factory_test_client::header_factory_test_client(bool _use_tcp) : + app_(vsomeip::runtime::get()->create_application()), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + blocked_(false), + is_available_(false), + number_of_messages_to_send_(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND), + number_of_sent_messages_(0), + number_of_acknowledged_messages_(0), + sender_(std::bind(&header_factory_test_client::run, this)) +{ +} + +bool header_factory_test_client::init() +{ + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&header_factory_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&header_factory_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&header_factory_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void header_factory_test_client::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void header_factory_test_client::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void header_factory_test_client::join_sender_thread(){ + sender_.join(); + + ASSERT_EQ(number_of_sent_messages_, number_of_acknowledged_messages_); +} + +void header_factory_test_client::on_state(vsomeip::state_type_e _state) +{ + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + } +} + +void header_factory_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) +{ + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) + { + if(is_available_ && !_is_available) + { + is_available_ = false; + } + else if(_is_available && !is_available_) + { + is_available_ = true; + send(); + } + } +} + +void header_factory_test_client::on_message(const std::shared_ptr<vsomeip::message>& _response) +{ + VSOMEIP_INFO << "Received a response from Service [" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_session() << "]"; + number_of_acknowledged_messages_++; + ASSERT_EQ(_response->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID); + ASSERT_EQ(_response->get_instance(), vsomeip_test::TEST_SERVICE_INSTANCE_ID); + ASSERT_EQ(_response->get_session(), + static_cast<vsomeip::session_t>(number_of_acknowledged_messages_)); + if(number_of_acknowledged_messages_ == number_of_messages_to_send_) { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } +} + +void header_factory_test_client::send() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); +} + +void header_factory_test_client::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + { + condition_.wait(its_lock); + } + blocked_ = false; + request_->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request_->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request_->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + for (uint32_t i = 0; i < number_of_messages_to_send_; i++) + { + app_->send(request_); + VSOMEIP_INFO << "Client/Session [" << std::setw(4) << std::setfill('0') + << std::hex << request_->get_client() << "/" << std::setw(4) + << std::setfill('0') << std::hex << request_->get_session() + << "] sent a request to Service [" << std::setw(4) + << std::setfill('0') << std::hex << request_->get_service() + << "." << std::setw(4) << std::setfill('0') << std::hex + << request_->get_instance() << "]"; + number_of_sent_messages_++; + } + // wait until all messages have been acknowledged + while (!blocked_) + { + condition_.wait(its_lock); + } + stop(); +} + +TEST(someip_header_factory_test, send_message_ten_times_test) +{ + bool use_tcp = false; + header_factory_test_client test_client_(use_tcp); + if (test_client_.init()) { + test_client_.start(); + test_client_.join_sender_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.hpp new file mode 100644 index 00000000000..79461b69681 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_client.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef HEADERFACTORYTESTCLIENT_HPP_ +#define HEADERFACTORYTESTCLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class header_factory_test_client +{ +public: + header_factory_test_client(bool _use_tcp); + bool init(); + void start(); + void stop(); + void join_sender_thread(); + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + void send(); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool is_available_; + std::uint32_t number_of_messages_to_send_; + std::uint32_t number_of_sent_messages_; + std::uint32_t number_of_acknowledged_messages_; + std::thread sender_; +}; + +#endif /* HEADERFACTORYTESTCLIENT_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.cpp new file mode 100644 index 00000000000..8f7255fe857 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.cpp @@ -0,0 +1,171 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <cstdlib> +#include <iomanip> + +#include "header_factory_test_service.hpp" + +header_factory_test_service::header_factory_test_service(bool _use_static_routing) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + use_static_routing_(_use_static_routing), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&header_factory_test_service::run, this)) +{ +} + +bool header_factory_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&header_factory_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&header_factory_test_service::on_state, this, + std::placeholders::_1)); + + VSOMEIP_INFO << "Static routing " << (use_static_routing_ ? "ON" : "OFF"); + return true; +} + +void header_factory_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void header_factory_test_service::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); + std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));}); + t.join(); +} + +void header_factory_test_service::join_offer_thread() +{ + offer_thread_.join(); +} + +void header_factory_test_service::offer() +{ + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void header_factory_test_service::stop_offer() +{ + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void header_factory_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void header_factory_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "]"; + + number_of_received_messages_++; + + ASSERT_EQ(_request->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID); + ASSERT_EQ(_request->get_method(), vsomeip_test::TEST_SERVICE_METHOD_ID); + + // Check the protocol version this shall be set to 0x01 according to the spec. + // TR_SOMEIP_00052 + ASSERT_EQ(_request->get_protocol_version(), 0x01); + // Check the message type this shall be 0xx (REQUEST) according to the spec. + // TR_SOMEIP_00055 + ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST); + + // check the session id. + ASSERT_EQ(_request->get_session(), static_cast<vsomeip::session_t>(number_of_received_messages_)); + + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); + + if(number_of_received_messages_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND) + { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ =true; + condition_.notify_one(); + } + ASSERT_LT(number_of_received_messages_, + vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + 1); +} + +void header_factory_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + blocked_ = false; + if(use_static_routing_) + { + offer(); + } + while (!blocked_) + condition_.wait(its_lock); + + std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));}); + t.join(); + app_->stop(); +} + +TEST(someip_header_factory_test, reveice_message_ten_times_test) +{ + bool use_static_routing = true; + header_factory_test_service test_service(use_static_routing); + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.hpp new file mode 100644 index 00000000000..7879946ac04 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/header_factory_tests/header_factory_test_service.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef HEADERFACTORYTESTSERVICE_HPP_ +#define HEADERFACTORYTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class header_factory_test_service +{ +public: + header_factory_test_service(bool _use_static_routing); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + bool use_static_routing_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; +}; + +#endif /* HEADERFACTORYTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/CMakeLists.txt new file mode 100644 index 00000000000..3242ec4b505 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/CMakeLists.txt @@ -0,0 +1,300 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(initial_event_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + initial_event_test_diff_client_ids_diff_ports_master.json + initial_event_test_diff_client_ids_diff_ports_master_tcp.json + initial_event_test_diff_client_ids_diff_ports_master_udp.json + initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json + initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json + initial_event_test_diff_client_ids_diff_ports_slave.json + initial_event_test_diff_client_ids_diff_ports_slave_tcp.json + initial_event_test_diff_client_ids_diff_ports_slave_udp.json + initial_event_test_diff_client_ids_partial_same_ports_master.json + initial_event_test_diff_client_ids_partial_same_ports_slave.json + initial_event_test_diff_client_ids_same_ports_master.json + initial_event_test_diff_client_ids_same_ports_master_tcp.json + initial_event_test_diff_client_ids_same_ports_master_udp.json + initial_event_test_diff_client_ids_same_ports_slave.json + initial_event_test_diff_client_ids_same_ports_slave_tcp.json + initial_event_test_diff_client_ids_same_ports_slave_udp.json + initial_event_test_master_starter.sh + initial_event_test_master_starter_qnx.sh + initial_event_test_same_client_ids_diff_ports_master.json + initial_event_test_same_client_ids_diff_ports_slave.json + initial_event_test_same_client_ids_same_ports_master.json + initial_event_test_same_client_ids_same_ports_slave.json + initial_event_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(initial_event_test_client + initial_event_test_client.cpp +) + +# Add test executable. +add_executable(initial_event_test_service + initial_event_test_service.cpp +) + +# Add test executable. +add_executable(initial_event_test_availability_checker + initial_event_test_availability_checker.cpp +) + +# Add test executable. +add_executable(initial_event_test_stop_service + initial_event_test_stop_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + initial_event_test_client + initial_event_test_service + initial_event_test_availability_checker + initial_event_test_stop_service +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Initial Events Tests - Single Event + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_diff_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_udp.json + UDP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_diff_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_tcp.json + TCP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_diff_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master.json + TCP_AND_UDP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_same_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_udp.json + UDP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_same_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_tcp.json + TCP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master.json + TCP_AND_UDP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_partial_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_partial_same_ports_master.json + TCP_AND_UDP +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_diff_ports_same_service_id_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json + TCP_AND_UDP SAME_SERVICE_ID +) + +# Initial Events Tests - Multiple Events + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_udp.json + UDP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_tcp.json + TCP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_udp_and_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_same_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_udp.json + UDP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_same_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_tcp.json + TCP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_partial_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_partial_same_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_same_service_id_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json + TCP_AND_UDP SAME_SERVICE_ID MULTIPLE_EVENTS +) + +# Initial Events Tests - Multiple Events, Subscribe On Availability + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_udp.json + UDP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_tcp.json + TCP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_udp_and_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_udp.json + UDP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master_tcp.json + TCP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_same_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_partial_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_partial_same_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_subscribe_on_availability_diff_client_ids_diff_ports_same_service_id_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json + TCP_AND_UDP SAME_SERVICE_ID MULTIPLE_EVENTS SUBSCRIBE_ON_AVAILABILITY +) + +# Initial Events Tests - Multiple Events, Subscribe Only One + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_udp.json + UDP MULTIPLE_EVENTS SUBSCRIBE_ONLY_ONE +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_tcp.json + TCP MULTIPLE_EVENTS SUBSCRIBE_ONLY_ONE +) + +# Add custom test command. +add_custom_test( + NAME initial_event_test_multiple_events_diff_client_ids_diff_ports_partial_subscription_udp_and_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master.json + TCP_AND_UDP MULTIPLE_EVENTS SUBSCRIBE_ONLY_ONE +) + +# Initial Events Tests - Subscribe Twice + +# Add custom test command. +add_custom_test( + NAME initial_event_test_diff_client_ids_diff_ports_client_subscribes_twice + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/initial_event_test_master_starter.sh + initial_event_test_diff_client_ids_diff_ports_master_udp.json + UDP CLIENT_SUBSCRIBES_TWICE +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..a8c17d26471 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_tcp.json.in new file mode 100644 index 00000000000..fb7b8ca6956 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_tcp.json.in @@ -0,0 +1,78 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_udp.json.in new file mode 100644 index 00000000000..40657eac469 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_master_udp.json.in @@ -0,0 +1,66 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003" + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in new file mode 100644 index 00000000000..363f6288d61 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1111", + "instance":"0x0002", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x1111", + "instance":"0x0003", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in new file mode 100644 index 00000000000..c0af842b77b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_same_service_id_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0002", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0003", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..be317ccdfc1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_tcp.json.in new file mode 100644 index 00000000000..33fb4b9413e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_tcp.json.in @@ -0,0 +1,79 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_udp.json.in new file mode 100644 index 00000000000..6aa86bf0a10 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_diff_ports_slave_udp.json.in @@ -0,0 +1,67 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006" + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in new file mode 100644 index 00000000000..927fda788e4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in new file mode 100644 index 00000000000..69d0bf87016 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_partial_same_ports_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..4a660fd6ba0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_tcp.json.in new file mode 100644 index 00000000000..21346a9213f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_tcp.json.in @@ -0,0 +1,78 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_udp.json.in new file mode 100644 index 00000000000..42a7e4267e2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_master_udp.json.in @@ -0,0 +1,66 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..2b948b16bc6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_tcp.json.in new file mode 100644 index 00000000000..db75e78efa8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_tcp.json.in @@ -0,0 +1,79 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_udp.json.in new file mode 100644 index 00000000000..10e7bb144cd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_diff_client_ids_same_ports_slave_udp.json.in @@ -0,0 +1,67 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x4444" + }, + { + "name":"initial_event_test_service_five", + "id":"0x5555" + }, + { + "name":"initial_event_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter.sh.in new file mode 100755 index 00000000000..bd46819f865 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter.sh.in @@ -0,0 +1,144 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 initial_event_test_diff_client_ids_diff_ports_master.json" + echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter" + echo "To ensure the first client only subscribes to one event pass SUBSCRIBE_ONLY_ONE as third/fourth parameter" + exit 1 +fi + +PASSED_JSON_FILE=$1 +# Remove processed options from $@ +shift 1 +REMAINING_OPTIONS="$@" + +print_starter_message () { + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting initial event test on slave LXC with params $CLIENT_JSON_FILE $REMAINING_OPTIONS" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/initial_event_tests; ./initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** initial_event_test_diff_client_ids_diff_ports_master.json and +** initial_event_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi +} + +# replace master with slave to be able display the correct json file to be used +# with the slave script +MASTER_JSON_FILE=$PASSED_JSON_FILE +CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave} + +FAIL=0 + +# Start the services +export VSOMEIP_CONFIGURATION=$PASSED_JSON_FILE + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_one +./initial_event_test_service 1 $REMAINING_OPTIONS & +PID_SERVICE_ONE=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_two +./initial_event_test_service 2 $REMAINING_OPTIONS & +PID_SERVICE_TWO=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_three +./initial_event_test_service 3 $REMAINING_OPTIONS & +PID_SERVICE_THREE=$! + +sleep 3 + +unset VSOMEIP_APPLICATION_NAME + +# Array for client pids +CLIENT_PIDS=() + +# Start first client which subscribes remotely +./initial_event_test_client 9000 DONT_EXIT $REMAINING_OPTIONS & +FIRST_PID=$! + +# Start availability checker in order to wait until the services on the remote +# were started as well +./initial_event_test_availability_checker 1234 $REMAINING_OPTIONS & +PID_AVAILABILITY_CHECKER=$! + +sleep 1 + +print_starter_message + +# remove SUBSCRIBE_ONLY_ONCE parameter from $REMAINING_OPTIONS to ensure the +# following clients subscribe normaly +REMAINING_OPTIONS=${REMAINING_OPTIONS%SUBSCRIBE_ONLY_ONE} +REMAINING_OPTIONS=${REMAINING_OPTIONS#SUBSCRIBE_ONLY_ONE} + + +# wait until the services on the remote node were started as well +echo "WAITING FOR SERVICE AVAILABILITY" +wait $PID_AVAILABILITY_CHECKER +echo "ALL SERVICES ARE AVAILABLE NOW" + +sleep 2 + +for client_number in $(seq 9001 9011) +do + ./initial_event_test_client $client_number STRICT_CHECKING $REMAINING_OPTIONS & + CLIENT_PIDS+=($!) +done + + +# Wait until all clients are finished +for job in ${CLIENT_PIDS[*]} +do + # Fail gets incremented if a client exits with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +echo "Starting stop service | Master" + +# wait until all clients exited on slave side +./initial_event_test_stop_service MASTER & +PID_STOP_SERVICE=$! +wait $PID_STOP_SERVICE + +# shutdown the first client +kill $FIRST_PID +wait $FIRST_PID || FAIL=$(($FAIL+1)) + +# shutdown the services +kill $PID_SERVICE_THREE +kill $PID_SERVICE_TWO +kill $PID_SERVICE_ONE + +sleep 1 + +# Check if they exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter_qnx.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter_qnx.sh.in new file mode 100755 index 00000000000..f302048a1a8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_master_starter_qnx.sh.in @@ -0,0 +1,163 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 initial_event_test_diff_client_ids_diff_ports_master.json" + echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter" + echo "To ensure the first client only subscribes to one event pass SUBSCRIBE_ONLY_ONE as third/fourth parameter" + exit 1 +fi + +PASSED_JSON_FILE=$1 +# Remove processed options from $@ +shift 1 +REMAINING_OPTIONS="$@" + +print_starter_message () { + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting initial event test on slave LXC with params $CLIENT_JSON_FILE $REMAINING_OPTIONS" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests; ./initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** initial_event_test_slave_starter.sh $CLIENT_JSON_FILE $REMAINING_OPTIONS +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** initial_event_test_diff_client_ids_diff_ports_master.json and +** initial_event_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi +} + +# replace master with slave to be able display the correct json file to be used +# with the slave script +MASTER_JSON_FILE=$PASSED_JSON_FILE +CLIENT_JSON_FILE="<corresponding-slave-json-for-$MASTER_JSON_FILE>" + +FAIL=0 + +# Start the services +export VSOMEIP_CONFIGURATION=$PASSED_JSON_FILE + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_one +./initial_event_test_service 1 $REMAINING_OPTIONS & +PID_SERVICE_ONE=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_two +./initial_event_test_service 2 $REMAINING_OPTIONS & +PID_SERVICE_TWO=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_three +./initial_event_test_service 3 $REMAINING_OPTIONS & +PID_SERVICE_THREE=$! + +sleep 3 + +unset VSOMEIP_APPLICATION_NAME + +# Start first client which subscribes remotely +./initial_event_test_client 9000 DONT_EXIT $REMAINING_OPTIONS & +FIRST_PID=$! + +# Start availability checker in order to wait until the services on the remote +# were started as well +./initial_event_test_availability_checker 1234 $REMAINING_OPTIONS & +PID_AVAILABILITY_CHECKER=$! + +sleep 1 + +print_starter_message + +# remove SUBSCRIBE_ONLY_ONCE parameter from $REMAINING_OPTIONS to ensure the +# following clients subscribe normaly +REMAINING_OPTIONS=${REMAINING_OPTIONS%SUBSCRIBE_ONLY_ONE} +REMAINING_OPTIONS=${REMAINING_OPTIONS#SUBSCRIBE_ONLY_ONE} + + +# wait until the services on the remote node were started as well +echo "WAITING FOR SERVICE AVAILABILITY" +wait $PID_AVAILABILITY_CHECKER +echo "ALL SERVICES ARE AVAILABLE NOW" + +sleep 2 + +./initial_event_test_client 9001 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_ONE=$! +./initial_event_test_client 9002 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_TWO=$! +./initial_event_test_client 9003 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_THREE=$! +./initial_event_test_client 9004 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_FOUR=$! +./initial_event_test_client 9005 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_FIVE=$! +./initial_event_test_client 9006 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_SIX=$! +./initial_event_test_client 9007 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_SEVEN=$! +./initial_event_test_client 9008 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_EIGHT=$! +./initial_event_test_client 9009 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_NINE=$! +./initial_event_test_client 9010 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_TEN=$! +./initial_event_test_client 9011 STRICT_CHECKING $REMAINING_OPTIONS & +CLIENT_PID_ELEVEN=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_THREE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_FOUR || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_FIVE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_SIX || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_SEVEN || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_EIGHT || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_NINE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TEN || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_ELEVEN || FAIL=$(($FAIL+1)) + +# wait until all clients exited on slave side +./initial_event_test_stop_service MASTER & +PID_STOP_SERVICE=$! +wait $PID_STOP_SERVICE + +# shutdown the first client +kill $FIRST_PID +wait $FIRST_PID || FAIL=$(($FAIL+1)) + +# shutdown the services +kill $PID_SERVICE_THREE +kill $PID_SERVICE_TWO +kill $PID_SERVICE_ONE + +sleep 1 +echo "" + +# Check if they exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..a8c17d26471 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..f60f8008044 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_diff_ports_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_five", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..4a660fd6ba0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_one", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_two", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x8888", + "instance":"0x0001", + "unreliable":"8888" + } + ], + "routing":"initial_event_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..670c5cc3356 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_same_client_ids_same_ports_slave.json.in @@ -0,0 +1,82 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "diagnosis" : "0x63", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"initial_event_test_service_four", + "id":"0x1111" + }, + { + "name":"initial_event_test_service_five", + "id":"0x2222" + }, + { + "name":"initial_event_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x9999", + "instance":"0x0001", + "unreliable":"9999" + } + ], + "routing":"initial_event_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_slave_starter.sh.in new file mode 100755 index 00000000000..55f573fecb6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/conf/initial_event_test_slave_starter.sh.in @@ -0,0 +1,104 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 initial_event_test_diff_client_ids_diff_ports_slave.json UDP" + echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter" + echo "To ensure the first client only subscribes to one event pass SUBSCRIBE_ONLY_ONE as third/fourth parameter" + exit 1 +fi + +PASSED_JSON_FILE=$1 +# Remove processed options from $@ +shift 1 +REMAINING_OPTIONS=$@ + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$PASSED_JSON_FILE + +# Start the services +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_four +./initial_event_test_service 4 $REMAINING_OPTIONS & +PID_SERVICE_FOUR=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_five +./initial_event_test_service 5 $REMAINING_OPTIONS & +PID_SERVICE_FIVE=$! + +export VSOMEIP_APPLICATION_NAME=initial_event_test_service_six +./initial_event_test_service 6 $REMAINING_OPTIONS & +PID_SERVICE_SIX=$! + +sleep 3 + +unset VSOMEIP_APPLICATION_NAME + +# Array for client pids +CLIENT_PIDS=() + +# Start first client which subscribes remotely +./initial_event_test_client 9000 DONT_EXIT $REMAINING_OPTIONS & +FIRST_PID=$! + +# remove SUBSCRIBE_ONLY_ONCE parameter from $REMAINING_OPTIONS to ensure the +# following clients subscribe normaly +REMAINING_OPTIONS=${REMAINING_OPTIONS%SUBSCRIBE_ONLY_ONE} +REMAINING_OPTIONS=${REMAINING_OPTIONS#SUBSCRIBE_ONLY_ONE} + +# Start availability checker in order to wait until the services on the remote +# were started as well +./initial_event_test_availability_checker 1234 $REMAINING_OPTIONS & +PID_AVAILABILITY_CHECKER=$! + +# wait until the services on the remote node were started as well +wait $PID_AVAILABILITY_CHECKER +sleep 2; +for client_number in $(seq 9001 9011) +do + ./initial_event_test_client $client_number STRICT_CHECKING $REMAINING_OPTIONS & + CLIENT_PIDS+=($!) +done + +# Wait until all clients are finished +for job in ${CLIENT_PIDS[*]} +do + # Fail gets incremented if a client exits with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +echo "Starting stop service | Slave" +# wait until all clients exited on master side +./initial_event_test_stop_service SLAVE & +PID_STOP_SERVICE=$! +wait $PID_STOP_SERVICE + +# shutdown the first client +kill $FIRST_PID +wait $FIRST_PID || FAIL=$(($FAIL+1)) + +# shutdown the services +kill $PID_SERVICE_SIX +kill $PID_SERVICE_FIVE +kill $PID_SERVICE_FOUR + +sleep 1 + +# Check if they exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_availability_checker.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_availability_checker.cpp new file mode 100644 index 00000000000..cbe76c2f756 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_availability_checker.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "initial_event_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class initial_event_test_availability_checker : public vsomeip_utilities::base_logger { +public: + initial_event_test_availability_checker(int _client_number, + std::array<initial_event_test::service_info, 7> _service_infos) : + vsomeip_utilities::base_logger("IETC", "INITIAL EVENT TEST AVAILABILITY CHECKER"), + client_number_(_client_number), + service_infos_(_service_infos), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + wait_for_stop_(true), + stop_thread_(std::bind(&initial_event_test_availability_checker::wait_for_stop, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&initial_event_test_availability_checker::on_state, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + for(const auto& i : service_infos_) { + if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) { + continue; + } + other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false; + app_->register_availability_handler(i.service_id, i.instance_id, + std::bind(&initial_event_test_availability_checker::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(i.service_id, i.instance_id); + } + + app_->start(); + } + + ~initial_event_test_availability_checker() { + stop_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + auto its_service = other_services_available_.find(std::make_pair(_service, _instance)); + if(its_service != other_services_available_.end()) { + if(its_service->second != _is_available) { + its_service->second = true; + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is available."; + + } + } + + if(std::all_of(other_services_available_.cbegin(), + other_services_available_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::instance_t>, bool>::value_type& v) { + return v.second;})) { + + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + } + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] all services are available. Going down"; + app_->clear_all_handler(); + app_->stop(); + } + +private: + int client_number_; + std::array<initial_event_test::service_info, 7> service_infos_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; +}; + +static int client_number; +static bool use_same_service_id; + +TEST(someip_initial_event_test, wait_for_availability_and_exit) +{ + if(use_same_service_id) { + initial_event_test_availability_checker its_sample(client_number, + initial_event_test::service_infos_same_service_id); + } else { + initial_event_test_availability_checker its_sample(client_number, + initial_event_test::service_infos); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a client number and subscription type, like: " << argv[0] << " 2 SAME_SERVICE_ID" << std::endl; + std::cerr << "Valid client numbers are from 0 to 0xFFFF" << std::endl; + std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl; + return 1; + } + + client_number = std::stoi(std::string(argv[1]), nullptr); + + if (argc >= 2) { + for (int i = 2; i < argc; i++) { + if (std::string("SAME_SERVICE_ID") == std::string(argv[i])) { + use_same_service_id = true; + std::cout << "Availability checker: Using same service ID" << std::endl; + } + } + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_client.cpp new file mode 100644 index 00000000000..8c8b81e0074 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_client.cpp @@ -0,0 +1,635 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#if defined(__linux__) || defined(ANDROID) +#include <signal.h> +#endif + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "initial_event_test_globals.hpp" + +class initial_event_test_client; +static initial_event_test_client* the_client; +extern "C" void signal_handler(int _signum); + +class initial_event_test_client { +public: + initial_event_test_client(int _client_number, + bool _service_offered_tcp_and_udp, + std::array<initial_event_test::service_info, 7> _service_infos, + bool _subscribe_on_available, std::uint32_t _events_to_subscribe, + bool _initial_event_strict_checking, + bool _dont_exit, bool _subscribe_only_one, + vsomeip::reliability_type_e _reliability_type, + bool _client_subscribes_twice) : + client_number_(_client_number), + service_infos_(_service_infos), + service_offered_tcp_and_udp_(_service_offered_tcp_and_udp), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + wait_for_stop_(true), + is_first(true), + subscribe_on_available_(_subscribe_on_available), + events_to_subscribe_(_events_to_subscribe), + initial_event_strict_checking_(_initial_event_strict_checking), + dont_exit_(_dont_exit), + subscribe_only_one_(_subscribe_only_one), + stop_thread_(&initial_event_test_client::wait_for_stop, this), + wait_for_signal_handler_registration_(true), + reliability_type_(_reliability_type), + client_subscribes_twice_(_client_subscribes_twice) + { + if (!app_->init()) { + stop_thread_.detach(); + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&initial_event_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&initial_event_test_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + for(const auto& i : service_infos_) { + if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) { + continue; + } + app_->register_availability_handler(i.service_id, i.instance_id, + std::bind(&initial_event_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(i.service_id, i.instance_id); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(i.eventgroup_id); + for (std::uint32_t j = 0; j < events_to_subscribe_; j++ ) { + app_->request_event(i.service_id, i.instance_id, + static_cast<vsomeip::event_t>(i.event_id + j), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + reliability_type_); + } + + other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false; + + if (!subscribe_on_available_) { + if (events_to_subscribe_ == 1) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR); + + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + other_services_received_notification_[std::make_pair(i.service_id, i.event_id)] = 0; + } else if (events_to_subscribe_ > 1) { + if (!subscribe_only_one_) { + for (std::uint32_t j = 0; j < events_to_subscribe_; j++ ) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR, + static_cast<vsomeip::event_t>(i.event_id + j)); + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + other_services_received_notification_[std::make_pair(i.service_id, i.event_id + j)] = 0; + } + } else { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR, + static_cast<vsomeip::event_t>(i.event_id)); + other_services_received_notification_[std::make_pair(i.service_id, i.event_id)] = 0; + } + } + } else { + for (std::uint32_t j = 0; j < events_to_subscribe_; j++ ) { + other_services_received_notification_[std::make_pair(i.service_id, i.event_id + j)] = 0; + } + } + } + + // Block all signals + sigset_t mask; + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + // start thread which handles all of the signals + signal_thread_ = std::thread(&initial_event_test_client::wait_for_signal, this); + { + std::unique_lock<std::mutex> its_lock(signal_mutex_); + while(wait_for_signal_handler_registration_) { + EXPECT_EQ(std::cv_status::no_timeout, + signal_condition_.wait_for(its_lock, std::chrono::seconds(10))); + } + wait_for_signal_handler_registration_ = true; + } + + app_->start(); + } + + ~initial_event_test_client() { + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + if (signal_thread_.joinable()) { + signal_thread_.join(); + } + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + auto its_service = other_services_available_.find(std::make_pair(_service, _instance)); + if(its_service != other_services_available_.end()) { + if(its_service->second != _is_available) { + its_service->second = true; + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is available."; + + } + } + + if(std::all_of(other_services_available_.cbegin(), + other_services_available_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::instance_t>, bool>::value_type& v) { + return v.second;})) { + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] all services are available."; + if (subscribe_on_available_) { + for(const auto& i : service_infos_) { + if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) { + continue; + } + if (events_to_subscribe_ == 1 ) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR); + } else if (events_to_subscribe_ > 1) { + for (std::uint32_t j = 0; j < events_to_subscribe_; j++ ) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR, + static_cast<vsomeip::event_t>(i.event_id + j)); + } + } + } + } + } + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + + { + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())]++; + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << "Received a notification with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "] (now have: " + << std::dec << other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())] << ")"; + } + + std::shared_ptr<vsomeip::payload> its_payload(_message->get_payload()); + EXPECT_EQ(2u, its_payload->get_length()); + EXPECT_EQ((_message->get_service() & 0xFF00 ) >> 8, its_payload->get_data()[0]); + EXPECT_EQ((_message->get_service() & 0xFF), its_payload->get_data()[1]); + bool notify(false); + if (client_subscribes_twice_) { + // only relevant for testcase: + // initial_event_test_diff_client_ids_same_ports_udp_client_subscribes_twice + // check that a second subscribe triggers another initial event + // expect notifications_to_send_after_double_subscribe == 2; + if (is_first) { + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + for(const auto& i : service_infos_) { + // subscribe again and expect initial events cached at rm::proxy to be received + // as configured routing manager only fires the event once after first susbcribe. + if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) { + continue; + } + if (!subscribe_on_available_) { + if (events_to_subscribe_ == 1) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR); + } else if (events_to_subscribe_ > 1) { + if (!subscribe_only_one_) { + for (std::uint32_t j = 0; j < events_to_subscribe_; j++ ) { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR, + static_cast<vsomeip::event_t>(i.event_id + j)); + } + } else { + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR, + static_cast<vsomeip::event_t>(i.event_id)); + } + } + } + } + is_first = false; + } else { + bool received_initial_event_twice(false); + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + received_initial_event_twice = all_notifications_received_twice(); + if (received_initial_event_twice) { + notify = true; + } + } + } else { + if (!service_offered_tcp_and_udp_) { + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + if (all_notifications_received()) { + notify = true; + } + } else { + if (all_notifications_received_tcp_and_udp()) { + notify = true; + } + } + } + + if (notify && !dont_exit_) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + } + } + } + + bool all_notifications_received() { + return std::all_of( + other_services_received_notification_.cbegin(), + other_services_received_notification_.cend(), + [&](const std::map<std::pair<vsomeip::service_t, + vsomeip::method_t>, std::uint32_t>::value_type& v) + { + bool result; + if (v.second == initial_event_test::notifications_to_send) { + result = true; + } else { + if (v.second >= initial_event_test::notifications_to_send) { + VSOMEIP_WARNING + << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second + << ". This is caused by StopSubscribe/Subscribe messages and/or" + << " service offered via UDP and TCP"; + if (initial_event_strict_checking_) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second; + } + result = initial_event_strict_checking_ ? false : true; + + } else { + result = false; + } + } + + return result; + } + ); + } + + bool all_notifications_received_twice() { + return std::all_of( + other_services_received_notification_.cbegin(), + other_services_received_notification_.cend(), + [&](const std::map<std::pair<vsomeip::service_t, + vsomeip::method_t>, std::uint32_t>::value_type& v) + { + bool result; + if (v.second == initial_event_test::notifications_to_send * 2) { + result = true; + } else { + if (v.second >= initial_event_test::notifications_to_send * 2) { + VSOMEIP_WARNING + << __func__ << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second + << ". This is caused by StopSubscribe/Subscribe messages and/or" + << " service offered via UDP and TCP"; + if (initial_event_strict_checking_) { + ADD_FAILURE() << __func__ << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second; + } + result = initial_event_strict_checking_ ? false : true; + + } else { + result = false; + } + } + return result; + } + ); + } + + bool all_notifications_received_tcp_and_udp() { + std::lock_guard<std::mutex> its_lock(received_notifications_mutex_); + std::uint32_t received_twice(0); + std::uint32_t received_normal(0); + for(const auto &v : other_services_received_notification_) { + if (!initial_event_strict_checking_ && + v.second > initial_event_test::notifications_to_send * 2) { + VSOMEIP_WARNING + << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << ". This is caused by StopSubscribe/Subscribe messages and/or" + << " service offered via UDP and TCP"; + received_twice++; + } else if (initial_event_strict_checking_ && + v.second > initial_event_test::notifications_to_send * 2) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received multiple initial events from service/instance: " + << std::setw(4) << std::setfill('0') << std::hex << v.first.first + << "." + << std::setw(4) << std::setfill('0') << std::hex << v.first.second + << " number of received events: " << v.second; + } else if (v.second == initial_event_test::notifications_to_send * 2) { + received_twice++; + } else if(v.second == initial_event_test::notifications_to_send) { + received_normal++; + } + } + + if( received_twice == ((service_infos_.size() - 1) * events_to_subscribe_)/ 2 + && received_normal == ((service_infos_.size() - 1) * events_to_subscribe_)/ 2) { + // routing manager stub receives the notification + // - twice from external nodes + // - and normal from all internal nodes + VSOMEIP_ERROR << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << "Received notifications:" + << " Normal: " << received_normal + << " Twice: " << received_twice; + return true; + } else if (initial_event_strict_checking_ && ( + received_twice > ((service_infos_.size() - 1) * events_to_subscribe_)/ 2)) { + ADD_FAILURE() << "[" << std::setw(4) << std::setfill('0') << std::hex + << client_number_ << "] " + << " Received too much initial events twice: " << received_twice; + } else if (received_normal == (events_to_subscribe_ * (service_infos_.size() - 1))) { + return true; + } + return false; + } + + void wait_for_signal() { + // register signal handler + the_client = this; + + sigset_t handler_mask; + sigemptyset(&handler_mask); + sigaddset(&handler_mask, SIGUSR1); + sigaddset(&handler_mask, SIGTERM); + sigaddset(&handler_mask, SIGINT); + sigaddset(&handler_mask, SIGABRT); + pthread_sigmask(SIG_UNBLOCK, &handler_mask, NULL); + + struct sigaction sa_new, sa_old; + sa_new.sa_handler = signal_handler; + sa_new.sa_flags = 0; + sigemptyset(&sa_new.sa_mask); + ::sigaction(SIGUSR1, &sa_new, &sa_old); + ::sigaction(SIGINT, &sa_new, &sa_old); + ::sigaction(SIGTERM, &sa_new, &sa_old); + ::sigaction(SIGABRT, &sa_new, &sa_old); + + { + std::lock_guard<std::mutex> its_lock(signal_mutex_); + wait_for_signal_handler_registration_ = false; + signal_condition_.notify_one(); + } + while (wait_for_stop_) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + void handle_signal(int _signum) { + (void)_signum; + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + } + + void wait_for_stop() { + static int its_call_number(0); + its_call_number++; + + { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait_for(its_lock, std::chrono::milliseconds(100)); + } + VSOMEIP_ERROR << "(" << std::dec << its_call_number << ") [" + << std::setw(4) << std::setfill('0') << std::hex + << client_number_ + << "] Received notifications from all services, going down"; + } + for (const auto& i : service_infos_) { + if (i.service_id == 0xFFFF && i.instance_id == 0xFFFF) { + continue; + } + app_->unsubscribe(i.service_id, i.instance_id, i.eventgroup_id); + } + app_->clear_all_handler(); + app_->stop(); + } + +private: + int client_number_; + std::array<initial_event_test::service_info, 7> service_infos_; + bool service_offered_tcp_and_udp_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + std::mutex received_notifications_mutex_; + std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + + std::atomic<bool> wait_for_stop_; + std::atomic<bool> is_first; + + bool subscribe_on_available_; + std::uint32_t events_to_subscribe_; + bool initial_event_strict_checking_; + bool dont_exit_; + bool subscribe_only_one_; + + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; + bool wait_for_signal_handler_registration_; + std::mutex signal_mutex_; + std::condition_variable signal_condition_; + std::thread signal_thread_; + vsomeip::reliability_type_e reliability_type_; + bool client_subscribes_twice_; +}; + +static int client_number; +static bool service_offered_tcp_and_udp; +static bool use_same_service_id; +static bool subscribe_on_available; +static std::uint32_t subscribe_multiple_events; +static bool initial_event_strict_checking; +static bool dont_exit; +static bool subscribe_only_one; +static bool client_subscribes_twice; + +vsomeip::reliability_type_e reliability_type = vsomeip::reliability_type_e::RT_UNKNOWN; + + +extern "C" void signal_handler(int signum) { + the_client->handle_signal(signum); +} + +TEST(someip_initial_event_test, wait_for_initial_events_of_all_services) +{ + if(use_same_service_id) { + initial_event_test_client its_sample(client_number, + service_offered_tcp_and_udp, + initial_event_test::service_infos_same_service_id, + subscribe_on_available, subscribe_multiple_events, + initial_event_strict_checking, dont_exit, + subscribe_only_one, + reliability_type, + client_subscribes_twice); + } else { + initial_event_test_client its_sample(client_number, service_offered_tcp_and_udp, + initial_event_test::service_infos, subscribe_on_available, + subscribe_multiple_events, initial_event_strict_checking, dont_exit, + subscribe_only_one, + reliability_type, + client_subscribes_twice); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + // Block all signals + sigset_t mask; + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + ::testing::InitGoogleTest(&argc, argv); + + if(argc < 2) { + std::cerr << "Please specify a client number, like: " << argv[0] << " 2 SUBSCRIBE_BEFORE_START SAME_SERVICE_ID" << std::endl; + std::cerr << "Valid client numbers are from 0 to 0xFFFF" << std::endl; + std::cerr << "After client number one/multiple of these flags can be specified:"; + std::cerr << " - SERVICE_OFFERED_TCP_AND_UDP flag. Set this if the service is offered via TCP and UDP" << std::endl; + std::cerr << " - Time of subscription, valid values: [SUBSCRIBE_ON_AVAILABILITY, SUBSCRIBE_BEFORE_START], default SUBSCRIBE_BEFORE_START" << std::endl; + std::cerr << " - SAME_SERVICE_ID flag. If set the test is run w/ multiple instances of the same service, default false" << std::endl; + std::cerr << " - MULTIPLE_EVENTS flag. If set the test will subscribe to multiple events in the eventgroup, default false" << std::endl; + std::cerr << " - STRICT_CHECKING flag. If set the test will only successfully finish if exactly the number of initial events were received (and not more). Default false" << std::endl; + std::cerr << " - DONT_EXIT flag. If set the test will not exit if all notifications have been received. Default false" << std::endl; + std::cerr << " - SUBSCRIBE_ONLY_ONE flag. If set the test will only subscribe to one event even if MULTIPLE_EVENTS is set. Default false" << std::endl; + return 1; + } + + client_number = std::stoi(std::string(argv[1]), nullptr); + + subscribe_on_available = false; + initial_event_strict_checking = false; + service_offered_tcp_and_udp = false; + use_same_service_id = false; + subscribe_multiple_events = 1; + dont_exit = false; + subscribe_only_one = false; + client_subscribes_twice = false; + if (argc > 2) { + for (int i = 2; i < argc; i++) { + if (std::string("SUBSCRIBE_ON_AVAILABILITY") == std::string(argv[i])) { + subscribe_on_available = true; + } else if (std::string("SUBSCRIBE_BEFORE_START") == std::string(argv[i])) { + subscribe_on_available = false; + } else if (std::string("SAME_SERVICE_ID") == std::string(argv[i])) { + use_same_service_id = true; + std::cout << "Using same service ID" << std::endl; + } else if (std::string("MULTIPLE_EVENTS") == std::string(argv[i])) { + subscribe_multiple_events = 5; + } else if (std::string("STRICT_CHECKING") == std::string(argv[i])) { + initial_event_strict_checking = true; + } else if (std::string("DONT_EXIT") == std::string(argv[i])) { + dont_exit = true; + } else if (std::string("SUBSCRIBE_ONLY_ONE") == std::string(argv[i])) { + subscribe_only_one = true; + } else if (std::string("TCP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_RELIABLE; + std::cout << "Using reliability type RT_RELIABLE" << std::endl; + } else if (std::string("UDP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_UNRELIABLE; + std::cout << "Using reliability type RT_UNRELIABLE" << std::endl; + } else if (std::string("TCP_AND_UDP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_BOTH; + std::cout << "Using reliability type RT_BOTH" << std::endl; + } else if (std::string("CLIENT_SUBSCRIBES_TWICE")== std::string(argv[i])) { + client_subscribes_twice = true; + std::cout << "Testing for initial event after a second subscribe from same client CLIENT_SUBSCRIBES_TWICE" << std::endl; + } + } + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_globals.hpp new file mode 100644 index 00000000000..ce69ea9ebeb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_globals.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ +#define SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ + +namespace initial_event_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; +}; + +static constexpr std::array<service_info, 7> service_infos = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 }, + { 0x2222, 0x1, 0x2222, 0x2222, 0x2000 }, + { 0x3333, 0x1, 0x3333, 0x3333, 0x3000 }, + // node 2 + { 0x4444, 0x1, 0x4444, 0x4444, 0x4000 }, + { 0x5555, 0x1, 0x5555, 0x5555, 0x5000 }, + { 0x6666, 0x1, 0x6666, 0x6666, 0x6000 } +}}; + +static constexpr std::array<service_info, 7> service_infos_same_service_id = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 }, + { 0x1111, 0x2, 0x2222, 0x2222, 0x2000 }, + { 0x1111, 0x3, 0x3333, 0x3333, 0x3000 }, + // node 2 + { 0x2222, 0x1, 0x4444, 0x4444, 0x4000 }, + { 0x2222, 0x2, 0x5555, 0x5555, 0x5000 }, + { 0x2222, 0x3, 0x6666, 0x6666, 0x6000 } +}}; + +static constexpr service_info stop_service_master = { 0x8888, 0x1, 0x8888, 0x0, 0x0 }; +static constexpr service_info stop_service_slave = { 0x9999, 0x1, 0x9999, 0x0, 0x0 }; + +static constexpr int notifications_to_send = 1; +} + +#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_service.cpp new file mode 100644 index 00000000000..a1cd03e78eb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_service.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "initial_event_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + + +class initial_event_test_service : public vsomeip_utilities::base_logger { +public: + initial_event_test_service(struct initial_event_test::service_info _service_info, + std::uint32_t _events_to_offer, vsomeip::reliability_type_e _reliability_type) : + vsomeip_utilities::base_logger("IETS", "INITIAL EVENT TEST SERVICE"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + events_to_offer_(_events_to_offer), + offer_thread_(std::bind(&initial_event_test_service::run, this)), + reliability_type_(_reliability_type) { + if (!app_->init()) { + offer_thread_.detach(); + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&initial_event_test_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + for (std::uint16_t i = 0; i < events_to_offer_; i++) { + app_->offer_event(service_info_.service_id, service_info_.instance_id, + static_cast<vsomeip::event_t>(service_info_.event_id + i), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + reliability_type_); + } + + // set value to field + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[2] = {static_cast<vsomeip::byte_t>((service_info_.service_id & 0xFF00) >> 8), + static_cast<vsomeip::byte_t>((service_info_.service_id & 0xFF))}; + its_payload->set_data(its_data, 2); + for (std::uint16_t i = 0; i < events_to_offer_; i++) { + app_->notify(service_info_.service_id, service_info_.instance_id, + static_cast<vsomeip::event_t>(service_info_.event_id + i), its_payload); + } + + app_->start(); + } + + ~initial_event_test_service() { + app_->stop(); + + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + } + condition_.notify_one(); + } + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + } + +private: + initial_event_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + std::uint32_t events_to_offer_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + vsomeip::reliability_type_e reliability_type_; +}; + +static unsigned long service_number; +static bool use_same_service_id; +static std::uint32_t offer_multiple_events; +vsomeip::reliability_type_e reliability_type = vsomeip::reliability_type_e::RT_UNKNOWN; + +TEST(someip_initial_event_test, set_field_once) +{ + if(use_same_service_id) { + initial_event_test_service its_sample( + initial_event_test::service_infos_same_service_id[service_number], offer_multiple_events, + reliability_type); + } else { + initial_event_test_service its_sample( + initial_event_test::service_infos[service_number], offer_multiple_events, + reliability_type); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number and subscription type, like: " << argv[0] << " 2 SAME_SERVICE_ID" << std::endl; + std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl; + std::cerr << "After the service number one/multiple of these flags can be specified:"; + std::cerr << " - SAME_SERVICE_ID flag. If set the test is run w/ multiple instances of the same service, default false" << std::endl; + std::cerr << " - MULTIPLE_EVENTS flag. If set the test will offer to multiple events in the eventgroup, default false" << std::endl; + return 1; + } + + service_number = std::stoul(std::string(argv[1]), nullptr); + + offer_multiple_events = 1; + use_same_service_id = false; + + if (argc > 2) { + for (int i = 2; i < argc; i++) { + if (std::string("SAME_SERVICE_ID") == std::string(argv[i])) { + use_same_service_id = true; + std::cout << "Using same service ID" << std::endl; + } else if (std::string("MULTIPLE_EVENTS") == std::string(argv[i])) { + offer_multiple_events = 5; + } else if (std::string("TCP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_RELIABLE; + std::cout << "Using reliability type RT_RELIABLE" << std::endl; + } else if (std::string("UDP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_UNRELIABLE; + std::cout << "Using reliability type RT_UNRELIABLE" << std::endl; + } else if (std::string("TCP_AND_UDP")== std::string(argv[i])) { + reliability_type = vsomeip::reliability_type_e::RT_BOTH; + std::cout << "Using reliability type RT_BOTH" << std::endl; + } + } + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_stop_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_stop_service.cpp new file mode 100644 index 00000000000..3e5bfd222bb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/initial_event_tests/initial_event_test_stop_service.cpp @@ -0,0 +1,292 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "initial_event_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class initial_event_test_stop_service : public vsomeip_utilities::base_logger { +public: + initial_event_test_stop_service(struct initial_event_test::service_info _service_info, bool _is_master) : + vsomeip_utilities::base_logger("IETS", "INITIAL EVENT TEST STOP SERVICE"), + service_info_(_service_info), + is_master_(_is_master), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + wait_until_stop_service_other_node_available_(true), + wait_until_shutdown_method_called_(true), + offer_thread_(std::bind(&initial_event_test_stop_service::run, this)), + wait_for_stop_(true), + stop_thread_(std::bind(&initial_event_test_stop_service::wait_for_stop, this)), + called_other_node_(false) { + if (!app_->init()) { + offer_thread_.detach(); + stop_thread_.detach(); + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&initial_event_test_stop_service::on_state, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&initial_event_test_stop_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + if (is_master_) { + app_->request_service( + initial_event_test::stop_service_slave.service_id, + initial_event_test::stop_service_slave.instance_id); + app_->register_availability_handler( + initial_event_test::stop_service_slave.service_id, + initial_event_test::stop_service_slave.instance_id, + std::bind(&initial_event_test_stop_service::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } else { + app_->request_service( + initial_event_test::stop_service_master.service_id, + initial_event_test::stop_service_master.instance_id); + app_->register_availability_handler( + initial_event_test::stop_service_master.service_id, + initial_event_test::stop_service_master.instance_id, + std::bind(&initial_event_test_stop_service::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } + app_->start(); + } + + ~initial_event_test_stop_service() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + if (stop_thread_.joinable()) { + stop_thread_.join(); + } + } + + void offer() { + if (is_master_) { + app_->offer_service( + initial_event_test::stop_service_master.service_id, + initial_event_test::stop_service_master.instance_id); + } else { + app_->offer_service( + initial_event_test::stop_service_slave.service_id, + initial_event_test::stop_service_slave.instance_id); + } + } + + void stop_offer() { + if (is_master_) { + app_->stop_offer_service( + initial_event_test::stop_service_master.service_id, + initial_event_test::stop_service_master.instance_id); + } else { + app_->stop_offer_service( + initial_event_test::stop_service_slave.service_id, + initial_event_test::stop_service_slave.instance_id); + } + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + bool notify(false); + if(_is_available) { + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service + << "." << _instance << "] is available."; + if(is_master_) { + if(_service == initial_event_test::stop_service_slave.service_id + && _instance == initial_event_test::stop_service_slave.instance_id) { + notify = true; + } + } else { + if(_service == initial_event_test::stop_service_master.service_id + && _instance == initial_event_test::stop_service_master.instance_id) { + notify = true; + } + } + } + if (notify) { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + wait_until_stop_service_other_node_available_ = false; + availability_condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST_NO_RETURN) { + VSOMEIP_DEBUG << "Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] shutdown method called"; + + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + } + } + + void run() { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + { + std::unique_lock<std::mutex> its_availability_lock(availability_mutex_); + while (wait_until_stop_service_other_node_available_) { + availability_condition_.wait(its_availability_lock); + } + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Calling shutdown method on remote side"; + + std::shared_ptr<vsomeip::message> msg(vsomeip::runtime::get()->create_request()); + msg->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + if(is_master_) { + msg->set_service(initial_event_test::stop_service_slave.service_id); + msg->set_instance(initial_event_test::stop_service_slave.instance_id); + msg->set_method(initial_event_test::stop_service_slave.method_id); + } else { + msg->set_service(initial_event_test::stop_service_master.service_id); + msg->set_instance(initial_event_test::stop_service_master.instance_id); + msg->set_method(initial_event_test::stop_service_master.method_id); + } + app_->send(msg); + called_other_node_ = true; + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_shutdown_method_called_) { + auto its_reason = condition_.wait_for(its_lock, std::chrono::milliseconds(250)); + if (its_reason == std::cv_status::timeout) { + its_lock.unlock(); + std::lock_guard<std::mutex> its_guard(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + wait_until_shutdown_method_called_ = false; + its_lock.lock(); + } + } + } + } + + void wait_for_stop() { + static int its_call_number(0); + its_call_number++; + { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + } + VSOMEIP_INFO << "(" << std::dec << its_call_number << ") [" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] shutdown method was called, going down"; + while(!called_other_node_) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + // let offer thread exit + { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + app_->clear_all_handler(); + app_->stop(); + } + +private: + initial_event_test::service_info service_info_; + bool is_master_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_; + + bool wait_until_registered_; + bool wait_until_stop_service_other_node_available_; + bool wait_until_shutdown_method_called_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + + std::mutex availability_mutex_; + std::condition_variable availability_condition_; + + std::atomic<bool> wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; + + std::atomic<bool> called_other_node_; +}; + +static bool is_master = false; + +TEST(someip_initial_event_test, wait_for_stop_method_to_be_called) +{ + if(is_master) { + initial_event_test_stop_service its_sample(initial_event_test::stop_service_master, is_master); + } else { + initial_event_test_stop_service its_sample(initial_event_test::stop_service_slave, is_master); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a valid type, like: " << argv[0] << " MASTER" << std::endl; + std::cerr << "Valid types are in the range of [MASTER,SLAVE]" << std::endl; + return 1; + } + + if (argc >= 2 && std::string("MASTER") == std::string(argv[1])) { + is_master = true; + } else if (argc >= 2 && std::string("SLAVE") == std::string(argv[1])){ + is_master = false; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/CMakeLists.txt new file mode 100644 index 00000000000..343093e30d7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(lazy_load_tests LANGUAGES CXX) + +if (TEST_SECURITY) + + # Configure necessary files into build folder. + set(configuration_files + lazy_load_test_start.sh + vsomeip/lazy_load_test_config.json + vsomeip/vsomeip_ext/1_1/vsomeip_security.json + vsomeip/vsomeip_policy_extensions.json + ) + configure_files("${configuration_files}") + + # Add test executable. + add_executable(lazy_load_test_service + lazy_load_test_service.cpp + ) + + # Add test executable. + add_executable(lazy_load_test_client + lazy_load_test_client.cpp + ) + + # Add test executable. + add_executable(lazy_load_test_lazy_client + lazy_load_test_lazy_client.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + lazy_load_test_service + lazy_load_test_client + lazy_load_test_lazy_client + ) + targets_link_default_libraries("${executables}") + targets_add_default_dependencies("${executables}") + + # Add custom test command. + add_custom_test( + NAME lazy_load_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/lazy_load_test_start.sh + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/lazy_load_test_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/lazy_load_test_start.sh.in new file mode 100755 index 00000000000..6a3b3381db0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/lazy_load_test_start.sh.in @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +export VSOMEIP_CONFIGURATION=/vsomeip/ +export VSOMEIP_APPLICATION_NAME=routingmanagerd +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +export VSOMEIP_APPLICATION_NAME=service-sample +./lazy_load_test_service & + +sleep 1 + +export VSOMEIP_CONFIGURATION=lazy_load_test_service_config.json +export VSOMEIP_APPLICATION_NAME=client-sample_normal +./lazy_load_test_client & + +sleep 2 + +export VSOMEIP_CONFIGURATION=/vsomeip/ +export VSOMEIP_APPLICATION_NAME=client-sample-lazy +# start lazy client with linux user id 1 and group id 1 to use the 1_1 folder in extensions +setpriv --reuid=1 --regid=1 --clear-groups ./lazy_load_test_lazy_client + +sleep 1 + +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/lazy_load_test_config.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/lazy_load_test_config.json.in new file mode 100644 index 00000000000..6cfbd80d7c3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/lazy_load_test_config.json.in @@ -0,0 +1,109 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample-normal", + "id" : "0x1255" + }, + { + "name" : "client-sample-lazy", + "id" : "0x1256" + }, + { + "name" : "routingmanagerd", + "id" : "0x1111" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x111", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x1234", + "instance" : "0x02", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "security" : + { + "check_credentials" : "true", + "allow_remote_clients" : "true", + "policies" : + [ + { + "credentials" : [ + {"uid" : "@TEST_UID@", "gid" : "@TEST_GID@"} , + {"uid" : "1", "gid" : "1"} + ], + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instances" : ["0x5678", "0x02"] + } + ] + } + }, + { + "credentials" : {"uid" : "@TEST_UID@", "gid" : "@TEST_GID@"}, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : + [ + { + "ids" : ["0x5678"], + "methods" : [ {"first" : "0x8421", "last" : "0x8422" }, "0x8001", "0x7777" ] + } + ] + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_ext/1_1/vsomeip_security.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_ext/1_1/vsomeip_security.json.in new file mode 100644 index 00000000000..c1b64997e66 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_ext/1_1/vsomeip_security.json.in @@ -0,0 +1,27 @@ +{ + "security" : + { + "policies" : + [ + { + "credentials" : { "uid" : "1", "gid" : "1" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : + [ + { + "ids" : ["0x02"], + "methods" : [ {"first" : "0x8421", "last" : "0x8422" }, "0x8002", "0x7777" ] + } + ] + } + ] + } + } + ] + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_policy_extensions.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_policy_extensions.json.in new file mode 100644 index 00000000000..5934604fb8f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/conf/vsomeip/vsomeip_policy_extensions.json.in @@ -0,0 +1,8 @@ +{ + "container_policy_extensions": + [ + { + "container": "@HOSTNAME@", "path": "../..@CMAKE_CURRENT_BINARY_DIR@/vsomeip/vsomeip_ext" + } + ] +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.cpp new file mode 100644 index 00000000000..e078374d7b8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "lazy_load_test_client.hpp" + +lazy_load_test_client::lazy_load_test_client() + : app_(vsomeip::runtime::get()->create_application()), + current_service_availability_status_(false), + sender_(std::bind(&lazy_load_test_client::run, this)), + received_responses_(0), + received_allowed_events_(0) {} + +bool lazy_load_test_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&lazy_load_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&lazy_load_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + TEST_INSTANCE_LAZY, vsomeip::ANY_METHOD, + std::bind(&lazy_load_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&lazy_load_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(SERVICE_TO_BE_REFUSED, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&lazy_load_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, + std::bind(&lazy_load_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void lazy_load_test_client::start() { + VSOMEIP_INFO << "Starting..."; + + app_->start(); +} + +void lazy_load_test_client::stop() { + VSOMEIP_INFO << "Stopping..."; + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->clear_all_handler(); + app_->stop(); +} + +void lazy_load_test_client::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "CLIENT ON_STATE..."; + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request not allowed service ID + app_->request_service(SERVICE_TO_BE_REFUSED, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request not allowed instance ID + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, false); + + // request events of eventgroup 0x01 which holds events 0x8001 (allowed) and 0x8002 (denied) + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(EVENT_GROUP); + + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_REFUSE), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, EVENT_GROUP, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT)); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, EVENT_GROUP, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(EVENT_TO_REFUSE)); + + } +} + +void lazy_load_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_service_available) { + + VSOMEIP_INFO << "CLIENT ON_AVAILABILITY..."; + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << '.' << _instance << "] is " + << (_is_service_available ? "available." : "NOT available."); + + // Check that only the allowed service is available + if (_is_service_available) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _service) + << "Unexpected Service ID on_availability"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _instance) + << "Unexpected Instance ID on_availability"; + } + if (vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if (current_service_availability_status_ && !_is_service_available) { + current_service_availability_status_ = false; + } else if (_is_service_available && !current_service_availability_status_) { + current_service_availability_status_ = true; + condition_.notify_one(); + } + } +} + +void lazy_load_test_client::on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << '.' + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << '/' + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << ']'; + + if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()) + << "Unexpected Service ID on_message response"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance()) + << "Unexpected Instance ID on_message response"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _response->get_method()) + << "Unexpected Method ID on_message response"; + + + if (_response->get_service() == vsomeip_test::TEST_SERVICE_SERVICE_ID && + _response->get_instance() == vsomeip_test::TEST_SERVICE_INSTANCE_ID && + _response->get_method() == vsomeip_test::TEST_SERVICE_METHOD_ID) { + received_responses_++; + if (received_responses_ == NUMBER_OF_MESSAGES_TO_SEND) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + } + } + + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + + // check that only allowed event 0x8001 is received for client-sample-a + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()) + << "Unexpected Service ID on_message notification"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance()) + << "Unexpected Instance ID on_message notification"; + EXPECT_EQ(EVENT_TO_ACCEPT, _response->get_method()) + << "Unexpected Method ID on_message notification"; + + received_allowed_events_++; + } +} + +void lazy_load_test_client::run() { + for (std::uint32_t i = 0; i < NUMBER_OF_MESSAGES_TO_SEND; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!current_service_availability_status_) { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + // send a request which is allowed by policy -> expect answer + app_->send(request); + + // send a request with a not allowed method ID -> expect no answer + request->set_method(METHOD_TO_BE_REFUSED); + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + EXPECT_EQ(NUMBER_OF_MESSAGES_TO_SEND, received_responses_) + << "Unexpected received_responses_ run()"; + EXPECT_EQ(received_allowed_events_, static_cast<std::uint32_t>(EXPECTED_EVENTS)) + << "Unexpected received_allowed_events run()"; + + stop(); +} + +void lazy_load_test_client::join_sender_thread() { + if (sender_.joinable()) { + sender_.join(); + } +} + +TEST(someip_lazy_load_test, normal_client) { + lazy_load_test_client test_client; + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.hpp new file mode 100644 index 00000000000..245ac1f2f34 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_client.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LAZY_LOAD_TEST_CLIENT_HPP +#define LAZY_LOAD_TEST_CLIENT_HPP + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" + +class lazy_load_test_client { +public: + lazy_load_test_client(); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool current_service_availability_status_; + + std::thread sender_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> received_allowed_events_; + + const std::uint16_t METHOD_TO_BE_REFUSED = 0x888; + const std::uint16_t SERVICE_TO_BE_REFUSED = 0x111; + const std::uint16_t TEST_INSTANCE_LAZY = 0x02; + const std::uint16_t EXPECTED_EVENTS = 0x01; + + const std::uint16_t EVENT_GROUP = 0x01; + const std::uint16_t EVENT_TO_ACCEPT = 0x8001; + const std::uint16_t EVENT_TO_REFUSE = 0x8002; + + const std::uint16_t NUMBER_OF_MESSAGES_TO_SEND = 10; + +}; + +#endif // LAZY_LOAD_TEST_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.cpp new file mode 100644 index 00000000000..8e9a68a60b9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.cpp @@ -0,0 +1,242 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "lazy_load_test_lazy_client.hpp" + +lazy_load_lazy_client::lazy_load_lazy_client() + : app_(vsomeip::runtime::get()->create_application()), + current_service_availability_status_(false), + sender_(std::bind(&lazy_load_lazy_client::run, this)), + received_responses_(0), + received_allowed_events_(0) {} + +bool lazy_load_lazy_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&lazy_load_lazy_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&lazy_load_lazy_client::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + TEST_INSTANCE_LAZY, vsomeip::ANY_METHOD, + std::bind(&lazy_load_lazy_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&lazy_load_lazy_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(SERVICE_TO_BE_REFUSED, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&lazy_load_lazy_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, + std::bind(&lazy_load_lazy_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void lazy_load_lazy_client::start() { + VSOMEIP_INFO << "Starting..."; + + app_->start(); +} + +void lazy_load_lazy_client::stop() { + VSOMEIP_INFO << "Stopping..."; + shutdown_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->clear_all_handler(); + app_->stop(); +} + +void lazy_load_lazy_client::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "CLIENT ON_STATE..."; + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + // request not allowed instance ID + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request not allowed service ID + app_->request_service(SERVICE_TO_BE_REFUSED, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, false); + + // request events of eventgroup 0x01 which holds events 0x8001 (denied) and 0x8002 (allowed) + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(EVENT_GROUP); + + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_REFUSE_LAZY), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, EVENT_GROUP, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(EVENT_TO_REFUSE_LAZY)); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, EVENT_GROUP, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY)); + } +} + +void lazy_load_lazy_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_service_available) { + + VSOMEIP_INFO << "CLIENT ON_AVAILABILITY..."; + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << '.' << _instance << "] is " + << (_is_service_available ? "available." : "NOT available."); + + // Check that only the allowed service is available + if (_is_service_available) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _service) + << "Unexpected Service ID on_available"; + EXPECT_EQ(TEST_INSTANCE_LAZY, _instance) + << "Unexpected Instance ID on_available"; + } + + if (vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && TEST_INSTANCE_LAZY == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if (current_service_availability_status_ && !_is_service_available) { + current_service_availability_status_ = false; + } else if (_is_service_available && !current_service_availability_status_) { + current_service_availability_status_ = true; + condition_.notify_one(); + } + } + +} + +void lazy_load_lazy_client::on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << '.' + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << '/' + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << ']'; + + if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()) + << "Unexpected Service ID on_message response"; + EXPECT_EQ(TEST_INSTANCE_LAZY, _response->get_instance()) + << "Unexpected Instance ID on_message response"; + EXPECT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _response->get_method()) + << "Unexpected Method ID on_message response"; + + + if (_response->get_service() == vsomeip_test::TEST_SERVICE_SERVICE_ID && + _response->get_method() == vsomeip_test::TEST_SERVICE_METHOD_ID) { + received_responses_++; + if (received_responses_ == NUMBER_OF_MESSAGES_TO_SEND) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + } + } + + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + + // check that only allowed event 0x8002 is received for client-sample-lazy + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()) + << "Unexpected Service ID on_message notification"; + EXPECT_EQ(TEST_INSTANCE_LAZY, _response->get_instance()) + << "Unexpected Instance ID on_message notification"; + EXPECT_EQ(EVENT_TO_ACCEPT_LAZY, _response->get_method()) + << "Unexpected Method ID on_message notification"; + received_allowed_events_++; + } +} + +void lazy_load_lazy_client::run() { + for (std::uint32_t i = 0; i < NUMBER_OF_MESSAGES_TO_SEND; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!current_service_availability_status_) { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(TEST_INSTANCE_LAZY); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + + // send a request which is allowed by policy -> expect answer + app_->send(request); + + // send a request with a not allowed method ID -> expect no answer + request->set_method(METHOD_TO_BE_REFUSED); + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(400)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + EXPECT_EQ(NUMBER_OF_MESSAGES_TO_SEND,received_responses_) + << "Unexpected received_responses_ run"; + EXPECT_EQ(received_allowed_events_, static_cast<std::uint32_t>(EXPECTED_EVENTS)) + << "Unexpected received_allowed_events_ run"; + + stop(); +} + +void lazy_load_lazy_client::join_sender_thread() { + if (sender_.joinable()) { + sender_.join(); + } +} + +void lazy_load_lazy_client::shutdown_service() { + VSOMEIP_INFO << "SHUTDOWN_SERVICE called from LAZY client"; + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(TEST_INSTANCE_LAZY); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request); +} + +TEST(someip_lazy_load_test, lazy_client) { + lazy_load_lazy_client test_lazy_client; + if (test_lazy_client.init()) { + test_lazy_client.start(); + test_lazy_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.hpp new file mode 100644 index 00000000000..0d8aaadb69c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_lazy_client.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LAZY_LOAD_TEST_LAZY_CLIENT_HPP +#define LAZY_LOAD_TEST_LAZY_CLIENT_HPP + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" + +class lazy_load_lazy_client { +public: + lazy_load_lazy_client(); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool current_service_availability_status_; + + std::thread sender_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> received_allowed_events_; + + const std::uint16_t METHOD_TO_BE_REFUSED = 0x888; + const std::uint16_t SERVICE_TO_BE_REFUSED = 0x111; + const std::uint16_t TEST_INSTANCE_LAZY = 0x02; + const std::uint16_t EXPECTED_EVENTS = 0x01; + + const std::uint16_t EVENT_GROUP = 0x01; + const std::uint16_t EVENT_TO_ACCEPT_LAZY = 0x8002; + const std::uint16_t EVENT_TO_REFUSE_LAZY = 0x8001; + + const std::uint16_t NUMBER_OF_MESSAGES_TO_SEND = 10; +}; + +#endif // LAZY_LOAD_TEST_LAZY_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.cpp new file mode 100644 index 00000000000..001bff656f3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.cpp @@ -0,0 +1,197 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "lazy_load_test_service.hpp" + +lazy_load_test_service::lazy_load_test_service() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&lazy_load_test_service::run, this)) {} + +bool lazy_load_test_service::init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&lazy_load_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&lazy_load_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + TEST_INSTANCE_LAZY, + vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&lazy_load_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&lazy_load_test_service::on_state, this, + std::placeholders::_1)); + + // offer eventgroup 0x01 + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(EVENT_GROUP); + + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_DEFAULT), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // also offer field 0x8002 which is not allowed to be received by client + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // Used with lazy client also offer field 0x8001 which is not allowed to be received by lazy client + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_DEFAULT), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // set value to fields + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[2]{ + static_cast<vsomeip::byte_t>((vsomeip_test::TEST_SERVICE_SERVICE_ID & 0xFF00) >> 8), + static_cast<vsomeip::byte_t>((vsomeip_test::TEST_SERVICE_SERVICE_ID & 0xFF)) + }; + its_payload->set_data(its_data, 2); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_DEFAULT), its_payload); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY), its_payload); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_DEFAULT), its_payload); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY, + static_cast<vsomeip::event_t>(EVENT_TO_ACCEPT_LAZY), its_payload); + + return true; +} + +void lazy_load_test_service::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void lazy_load_test_service::stop() { + VSOMEIP_INFO << "Stopping..."; + stop_offer(); + app_->clear_all_handler(); + app_->stop(); +} + +void lazy_load_test_service::join_offer_thread() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void lazy_load_test_service::offer() { + // Instance used by client a + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + + // Instance used by client b + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY); + + // try to offer a not allowed service ID 0x111 (client requesting the service should not get available) + app_->offer_service(SERVICE_TO_BE_REFUSED, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void lazy_load_test_service::stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, TEST_INSTANCE_LAZY); +} + +void lazy_load_test_service::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } else { + is_registered_ = false; + } +} + +void lazy_load_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) { + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _request->get_method()); + + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << '/' + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "] method: " << _request->get_method() + << " Instance ID: " << _request->get_instance(); + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + VSOMEIP_INFO << "service on_message response service : " << its_response->get_service(); + app_->send(its_response); + + number_of_received_messages_++; + if (number_of_received_messages_ == NUMBER_OF_MESSAGES_TO_RECEIVE) { + VSOMEIP_INFO << "Received all messages!"; + } +} + +void lazy_load_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>&) { + VSOMEIP_INFO << "Shutdown method was called, going down now."; + stop(); +} + +void lazy_load_test_service::run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_lazy_load_test, service) { + lazy_load_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#ifdef __linux__ +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.hpp new file mode 100644 index 00000000000..fa347b509f2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/lazy_load_test_service.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LAZY_LOAD_TEST_SERVICE_HPP +#define LAZY_LOAD_TEST_SERVICE_HPP + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" + +class lazy_load_test_service { +public: + lazy_load_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; + + const std::uint16_t SERVICE_TO_BE_REFUSED = 0x111; + const std::uint16_t TEST_INSTANCE_LAZY = 0x02; + + const std::uint16_t EVENT_GROUP = 0x01; + const std::uint16_t EVENT_TO_ACCEPT_LAZY = 0x8002; + const std::uint16_t EVENT_TO_ACCEPT_DEFAULT = 0x8001; + + // Twice as big as messages to send, account for all messages from both clients + const std::uint16_t NUMBER_OF_MESSAGES_TO_RECEIVE = 20; +}; + +#endif // LAZY_LOAD_TEST_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/readme b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/readme new file mode 100644 index 00000000000..e58f99bba68 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/lazy_load_tests/readme @@ -0,0 +1,112 @@ +Lazy Load Test + +Quick description: + +client-sample-normal: communicates with service id 0x1234, instance id 0x5678 without utilizing lazy loading. +client-sample-lazy: communicates with service id 0x1234, instance id 0x02. + +During the test registrations are made to the 0x01 eventgroup for both cases. +the normal client expects to receive the event 0x8001 while the lazy client expects the 0x8002 event. + +Multiple messages are then sent to the 0x8421, and the 0x888 methods of the respective service/instance for each test. Only responses from 0x8421 are expected. + +Details: + +Configs +The lazy load tests consists of 3 config jsons. +Two are configured json.in files, one is a direct json. + +-The lazy_load_test_config.json.in contains the basic app information: + --logging + + default configs + + --applications + + This tests uses 4 applications + "service-sample", "id" : "0x1277" runs the service app and will receive the requests from the clients + "client-sample-normal", "id" : "0x1255" client normal + "client-sample-lazy", "id" : "0x1256" client lazy + "routingmanagerd", "id" : "0x1111" in charge of the routing + + --services + + the list of services to be used in the app + service : "0x1234" holds 2 instance 0x5678 to interact with client a and 0x02 lazy client + service : "0x111" a dummy service which will not be permitted to be offered by policies + + --security: + + The security policy included in this json has the check_credentials set to true to enable the security feature to use Linux UserId and GroupId as credentials. + it always includes a policy that enables the offers of the service 0x1234 instances 0x5678 and 0x02 for the given credentials 0 0 and 1 1 + And holds the request part of the 0 0 credential (client sample) + + The request part of the security for lazy client is loaded subsequently by lazy loading + + --routing + + Routing will be handled by the routingmanagerd app + + --service discovery + default configs + +-The vsomeip_policy_extensions.json.in contains the container_policy_extensions which is a key value pair of the host container to the path of the vsomeip_security.json + +-The vsomeip_security.json contains the security policy for the requests allowed to credentials 1 1 (client-sample-lazy) + + + +The test + +Routingmanagerd app + The routingmanagerd app is brought up using the /vsomeip/ folder as its VSOMEIP_CONFIGURATION + Forcing it to parse the entire folder, and load the lazy_load_test_config.json + as well as the vsomeip_policy_extenions.json + The routingmanagerd is the routing manager and will handle communications between vsomeip apps. + +Service-sample app + The service-sample app is brought up using the same path as the routingmanagerd app. + The service-sample app offers 3 services + service 0x1234, instance 0x5678 (instance to interact with client-sample-normal due to security) + service 0x1234, instance 0x02 (instance to interact with client-sample-lazy due to security) + service 0x111, instance 0x5678 (dummy services offered, to be denied by security policies) + + The service 0x1234 + Contains an eventgroup 0x01 which has two offered events 0x8001 and 0x8002 + Both those events are populated with the payload 1234 and notified + Shutdown method 0x7777, used to shutdown the whole app + Method TEST_SERVICE_METHOD_ID = 0x8421 the method which will receive messages from the clients + + The service 0x111 + Offered but the security policies should prohibit the offer from happening. + Expect no interactions + + The test verifies the service-sample only receives message for the 0x1234 service and 0x8421 method + +Client-sample-normal app + The client-sample-normal app is brought up using direct injection of the lazy_load_test_config.json it will not undergo the lazy load process, used and will be used as the control case in this test. + + The app is initialized, request handlers are registered. + Upon registration of the app (app_state = registered) the client will request all three services offered by the service-sample. The on_availibity handler is the same for all 3 services. And tries to subscribe to both event of the 0x1234 0x5678 eventgroup 0x01 event 0x8001 and 0x8002 + + The first step of the test is to check that only the service 0x1234 instance 0x5678 becomes available to client-sample-normal + + The second step is to verify that only the notification from 0x8001 is received + + The third and final step is to send NUMBER_OF_MESSAGES_TO_SEND (32 as of writing this read me) messages to method 0x8421 and 0x888 of 0x1234 0x02 only responses from 0x8421 are expected. The tests expect to receive a total of NUMBER_OF_MESSAGES_TO_SEND + +Client-sample-lazy app + The client-sample-lazy app is brought up using the /vsomeip/ folder as its VSOMEIP_CONFIGURATION + Forcing it to parse the entire folder, and load the lazy_load_test_config.json + as well as the vsomeip_policy_extenions.json as well as execute the lazy loading of the vsomeip_security.json in the /vsomeip/vsomeip_ext/1_1/ folder + client-sample-lazy is the test case for lazy loading. + client-sample-lazy uses linux user-id uid: 1 and group-id gid: 1 + + The app is initialized, request handlers are registered. + Upon registration of the app (app_state = registered) the client will request all three services offered by the service-sample. The on_availibity handler is the same for all 3 services. And tries to subscribe to both event of the 0x1234 0x02 eventgroup 0x01 event 0x8001 and 0x8002 + + The first step of the test is to check that only the service 0x1234 instance 0x02 becomes available to client-sample-lazy + + The second step is to verify that only the notification from 0x8002 is received + + The third and final step is to send NUMBER_OF_MESSAGES_TO_SEND messages to method 0x8421 and 0x888 of 0x1234 0x02 only responses from 0x8421 are expected. The tests expect to receive a total of NUMBER_OF_MESSAGES_TO_SEND diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/CMakeLists.txt new file mode 100644 index 00000000000..36e77a85d27 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(magic_cookies_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + magic_cookies_test_client.json + magic_cookies_test_client_start.sh + magic_cookies_test_service.json + magic_cookies_test_service_start.sh + magic_cookies_test_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(magic_cookies_test_client + magic_cookies_test_client.cpp +) + +# Add test executable. +add_executable(magic_cookies_test_service + magic_cookies_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + magic_cookies_test_client + magic_cookies_test_service +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Link thread libraries to executables. +foreach(target ${executables}) + target_link_libraries(${target} ${CMAKE_THREAD_LIBS_INIT}) +endforeach() + +# Add custom test command. +add_custom_test( + NAME magic_cookies_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/magic_cookies_test_starter.sh + TIMEOUT 250 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client.json.in new file mode 100644 index 00000000000..bcb2e29705f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client.json.in @@ -0,0 +1,85 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "netmask":"255.255.255.0", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"true", + "path":"/var/log/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"magic_cookies_test_client", + "id":"0x1343" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "unicast":"@TEST_IP_MASTER@", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"true" + }, + "events": + [ + { + "event":"0x0777", + "is_field":"true" + }, + { + "event":"0x0778", + "is_field":"false" + }, + { + "event":"0x0779", + "is_field":"true" + } + ], + "eventgroups": + [ + { + "eventgroup":"0x4455", + "events": + [ + "0x777", + "0x778" + ] + }, + { + "eventgroup":"0x4465", + "events": + [ + "0x778", + "0x779" + ] + }, + { + "eventgroup":"0x4555", + "events": + [ + "0x777", + "0x779" + ] + } + ] + } + ], + "routing":"magic_cookies_test_client", + "service-discovery": + { + "enable":"false", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client_start.sh.in new file mode 100755 index 00000000000..45f4d3ced00 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_client_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=magic_cookies_test_client +export VSOMEIP_CONFIGURATION=magic_cookies_test_client.json +./magic_cookies_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service.json.in new file mode 100644 index 00000000000..dd52728907d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service.json.in @@ -0,0 +1,88 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"debug", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"magic_cookies_test_service", + "id":"0x1277" + } + ], + "services": + [ + { + "service":"0x1234", + "instance":"0x5678", + "reliable": + { + "port":"30509", + "enable-magic-cookies":"true" + }, + "events": + [ + { + "event":"0x0777", + "is_field":"false", + "is_reliable":"true", + "update-cycle":"2000" + }, + { + "event":"0x0778", + "is_field":"true", + "is_reliable":"true", + "update-cycle":"0" + }, + { + "event":"0x0779", + "is_field":"false", + "is_reliable":"true" + } + ], + "eventgroups": + [ + { + "eventgroup":"0x4455", + "events": + [ + "0x777", + "0x778" + ] + }, + { + "eventgroup":"0x4465", + "events": + [ + "0x778", + "0x779" + ] + }, + { + "eventgroup":"0x4555", + "events": + [ + "0x777", + "0x779" + ] + } + ] + } + ], + "routing":"magic_cookies_test_service", + "service-discovery": + { + "enable":"false", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service_start.sh.in new file mode 100755 index 00000000000..9288b7e032e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=magic_cookies_test_service +export VSOMEIP_CONFIGURATION=magic_cookies_test_service.json +./magic_cookies_test_service --tcp --static-routing diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_starter.sh.in new file mode 100755 index 00000000000..d077b149ea3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/conf/magic_cookies_test_starter.sh.in @@ -0,0 +1,59 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit successfully. + +# Display a message to show the user that he must now call the external service +# to finish the test successfully + +FAIL=0 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting magic cookies test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/magic_cookies_tests; ./magic_cookies_test_client_start.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./magic_cookies_test_client_start.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** magic_cookies_test_client_start.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** magic_cookies_client.json and +** magic_cookies_service.json to your personal setup. +** +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Start the client for magic-cookies test +export VSOMEIP_APPLICATION_NAME=magic_cookies_test_service +export VSOMEIP_CONFIGURATION=magic_cookies_test_service.json +./magic_cookies_test_service --tcp --static-routing & + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if client and server both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_client.cpp new file mode 100644 index 00000000000..f7887367e29 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_client.cpp @@ -0,0 +1,248 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <memory> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> +#include "../implementation/runtime/include/application_impl.hpp" +#include "../implementation/routing/include/routing_manager.hpp" + +class magic_cookies_test_client : public vsomeip_utilities::base_logger { +public: + magic_cookies_test_client() + : vsomeip_utilities::base_logger("MCTC", "MAGIC COOKIES TEST CLIENT"), + app_(new vsomeip::application_impl("", "")), + is_blocked_(false), + sent_messages_good_(8), + sent_messages_bad_(7), + received_responses_(0), + received_errors_(0), + wait_for_replies_(true), + runner_(std::bind(&magic_cookies_test_client::run, this)) { + } + + void init() { + VSOMEIP_INFO << "Initializing..."; + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + exit(EXIT_FAILURE); + } + + app_->register_state_handler( + std::bind( + &magic_cookies_test_client::on_state, + this, + std::placeholders::_1)); + + app_->register_message_handler( + vsomeip::ANY_SERVICE, vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&magic_cookies_test_client::on_message, + this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&magic_cookies_test_client::on_availability, + this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), + vsomeip::DEFAULT_MAJOR, vsomeip::DEFAULT_MINOR); + } + + void start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); + } + + void stop() { + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + VSOMEIP_INFO << "Client registration done."; + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip::ANY_MAJOR, vsomeip::ANY_MINOR); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available."); + + if (vsomeip_test::TEST_SERVICE_SERVICE_ID == _service && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + static bool is_available = false; + if (is_available && !_is_available) is_available = false; + else if (_is_available && !is_available) { + is_available = true; + std::lock_guard< std::mutex > its_lock(mutex_); + is_blocked_ = true; + condition_.notify_one(); + } + } + } + + void on_message(const std::shared_ptr< vsomeip::message > &_response) { + if (_response->get_return_code() == vsomeip::return_code_e::E_OK) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + received_responses_++; + } else if (_response->get_return_code() == vsomeip::return_code_e::E_MALFORMED_MESSAGE) { + VSOMEIP_INFO << "Received an error message from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + received_errors_++; + } + if (received_errors_ == sent_messages_bad_ + && received_responses_ == sent_messages_good_) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_replies_ = false; + condition_.notify_one(); + } + } + + void join() { + runner_.join(); + } + + void run() { + std::unique_lock< std::mutex > its_lock(mutex_); + while (!is_blocked_) { + if (std::cv_status::timeout == + condition_.wait_for(its_lock, std::chrono::milliseconds(5000))) { + GTEST_NONFATAL_FAILURE_("Service didn't become available within 5s."); + break; + } + } + VSOMEIP_INFO << "Running..."; + + vsomeip::routing_manager *its_routing = app_->get_routing_manager(); + + vsomeip::byte_t its_good_payload_data[] = { + 0x12, 0x34, 0x84, 0x21, + 0x00, 0x00, 0x00, 0x11, + 0x13, 0x43, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 + }; + + vsomeip::byte_t its_bad_payload_data[] = { + 0x12, 0x34, 0x84, 0x21, + 0x00, 0x00, 0x01, 0x23, + 0x13, 0x43, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 + }; + + // Test sequence + its_good_payload_data[11] = 0x01; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x02; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x03; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x04; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x05; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x06; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x07; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x08; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x09; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x0A; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x0B; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x0C; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x0D; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_bad_payload_data[11] = 0x0E; + its_routing->send(0x1343, its_bad_payload_data, sizeof(its_bad_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + std::this_thread::sleep_for(std::chrono::seconds(11)); + its_good_payload_data[11] = 0x0F; + its_routing->send(0x1343, its_good_payload_data, sizeof(its_good_payload_data), vsomeip_test::TEST_SERVICE_INSTANCE_ID, true); + + while (wait_for_replies_) { + if(std::cv_status::timeout == + condition_.wait_for(its_lock, std::chrono::milliseconds(5000))) { + GTEST_NONFATAL_FAILURE_("Didn't receive all replies/errors in time"); + break; + } + } + EXPECT_EQ(sent_messages_good_, received_responses_); + EXPECT_EQ(sent_messages_bad_, received_errors_); + stop(); + } + +private: + std::shared_ptr< vsomeip::application_impl > app_; + std::mutex mutex_; + std::condition_variable condition_; + bool is_blocked_; + const std::uint32_t sent_messages_good_; + const std::uint32_t sent_messages_bad_; + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> received_errors_; + bool wait_for_replies_; + std::thread runner_; +}; + +TEST(someip_magic_cookies_test, send_good_and_bad_messages) +{ + magic_cookies_test_client its_client; + its_client.init(); + its_client.start(); + its_client.join(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_service.cpp new file mode 100644 index 00000000000..49cda1e1c44 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/magic_cookies_tests/magic_cookies_test_service.cpp @@ -0,0 +1,170 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class magic_cookies_test_service : public vsomeip_utilities::base_logger { +public: + magic_cookies_test_service(bool _use_static_routing) : + vsomeip_utilities::base_logger("MGTS", "MAGIC COOKIES TEST SERVICE"), + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + use_static_routing_(_use_static_routing), + blocked_(false), + offer_thread_(std::bind(&magic_cookies_test_service::run, this)) { + } + + ~magic_cookies_test_service() { + offer_thread_.join(); + } + void init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + exit(EXIT_FAILURE); + } + app_->register_message_handler( + vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&magic_cookies_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&magic_cookies_test_service::on_state, this, + std::placeholders::_1)); + + VSOMEIP_INFO<< "Static routing " << (use_static_routing_ ? "ON" : "OFF"); + } + + void start() { + app_->start(); + } + + void offer() { + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + } + + void stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + if (!is_registered_) { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + } else { + is_registered_ = false; + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_request) { + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "]"; + + std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get() + ->create_response(_request); + + std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get() + ->create_payload(); + std::vector<vsomeip::byte_t> its_payload_data; + for (std::size_t i = 0; i < 120; ++i) + its_payload_data.push_back(static_cast<vsomeip::byte_t>(i % 256)); + its_payload->set_data(its_payload_data); + its_response->set_payload(its_payload); + + app_->send(its_response); + if(_request->get_session() == 0x0F) { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + bool is_offer(true); + blocked_ = false; + + if (use_static_routing_) { + offer(); + while (!blocked_) { + if(std::cv_status::timeout == + condition_.wait_for(its_lock, std::chrono::seconds(200))) { + GTEST_NONFATAL_FAILURE_("Didn't receive all requests within time"); + break; + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + app_->clear_all_handler(); + app_->stop(); + } else { + while (true) { + if (is_offer) + offer(); + else + stop_offer(); + std::this_thread::sleep_for(std::chrono::milliseconds(10000)); + is_offer = !is_offer; + } + } + } + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + bool use_static_routing_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::thread offer_thread_; +}; + +static bool use_static_routing = false; + +TEST(someip_magic_cookies_test, reply_to_good_messages) +{ + magic_cookies_test_service its_sample(use_static_routing); + its_sample.init(); + its_sample.start(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + std::string static_routing_enable("--static-routing"); + for (int i = 1; i < argc; i++) { + if (static_routing_enable == argv[i]) { + use_static_routing = true; + } + } + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/CMakeLists.txt new file mode 100644 index 00000000000..c4ac4d958dd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/CMakeLists.txt @@ -0,0 +1,96 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(malicious_data_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + malicious_data_test_master.json + malicious_data_test_master_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(malicious_data_test_service + malicious_data_test_service.cpp +) + +# Add test executable. +set(service_discovery_sources + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/configuration_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/entry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/eventgroupentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ip_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv4_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv6_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/load_balancing_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_element_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/protection_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/selective_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/serviceentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/unknown_option_impl.cpp +) +set(message_sources + ${CMAKE_SOURCE_DIR}/implementation/message/src/deserializer.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/payload_impl.cpp +) +add_executable(malicious_data_test_msg_sender + malicious_data_test_msg_sender.cpp + ${service_discovery_sources} + ${message_sources} +) + +# Link the vsomeip-sd library to the executable. +target_link_libraries(malicious_data_test_msg_sender + ${VSOMEIP_NAME}-sd +) + +# Add build dependencies and link libraries to executables. +set(executables + malicious_data_test_service + malicious_data_test_msg_sender +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME malicious_data_test_events + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/malicious_data_test_master_starter.sh MALICIOUS_EVENTS + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME malicious_data_test_protocol_version + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/malicious_data_test_master_starter.sh PROTOCOL_VERSION + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME malicious_data_test_message_type + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/malicious_data_test_master_starter.sh MESSAGE_TYPE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME malicious_data_test_return_code + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/malicious_data_test_master_starter.sh RETURN_CODE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME malicious_data_test_wrong_header_fields_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/malicious_data_test_master_starter.sh WRONG_HEADER_FIELDS_UDP + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master.json.in new file mode 100644 index 00000000000..d16fc32d380 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master.json.in @@ -0,0 +1,44 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "malicious_data_test_service", + "id" : "0x4289", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3345", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.24.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in new file mode 100755 index 00000000000..301ecfa4b30 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/conf/malicious_data_test_master_starter.sh.in @@ -0,0 +1,73 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +if [ $# -lt 1 ] +then + echo "Please pass a test mode to this script." + echo "For example: $0 MALICIOUS_EVENTS" + echo "Valid subscription types include:" + echo " [MALICIOUS_EVENTS, PROTOCOL_VERSION, MESSAGE_TYPE, RETURN_CODE, WRONG_HEADER_FIELDS_UDP]" + exit 1 +fi +TESTMODE=$1 + +export VSOMEIP_CONFIGURATION=malicious_data_test_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the services +./malicious_data_test_service $TESTMODE & +PID_SERIVCE=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/malicious_data_tests; ./malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && sleep 10; ./malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** malicious_data_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** malicious_data_test_master.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +for job in $PID_SERIVCE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_globals.hpp new file mode 100644 index 00000000000..de14d5e5c16 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_globals.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MALICIOUS_DATA_TEST_GLOBALS_HPP_ +#define MALICIOUS_DATA_TEST_GLOBALS_HPP_ + +namespace malicious_data_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::method_t notify_method_id; +}; + +struct service_info service = { 0x3344, 0x1, 0x1111, 0x8002, 0x1, 0x1404, 0x4242 }; + +enum test_mode_e { + MALICIOUS_EVENTS, + PROTOCOL_VERSION, + MESSAGE_TYPE, + RETURN_CODE, + WRONG_HEADER_FIELDS_UDP +}; + +} + +#endif /* MALICIOUS_DATA_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_msg_sender.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_msg_sender.cpp new file mode 100644 index 00000000000..f5f15927e5e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_msg_sender.cpp @@ -0,0 +1,1592 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iostream> +#include <memory> +#include <thread> +#include <chrono> +#include <cstring> +#include <future> + +#include <gtest/gtest.h> + +#include <boost/asio.hpp> + +#include <vsomeip/vsomeip.hpp> + +#include "../../implementation/utility/include/bithelper.hpp" +#include "../../implementation/message/include/deserializer.hpp" +#include "../../implementation/service_discovery/include/service_discovery.hpp" +#include "../../implementation/service_discovery/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/constants.hpp" +#include "../../implementation/service_discovery/include/enumeration_types.hpp" +#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp" +#include "../../implementation/service_discovery/include/serviceentry_impl.hpp" +#include "../../implementation/message/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/option_impl.hpp" +#include "../../implementation/service_discovery/include/ipv4_option_impl.hpp" +#include "malicious_data_test_globals.hpp" + +static char* remote_address; +static char* local_address; + +class malicious_data : public ::testing::Test { +public: + malicious_data() : + work_(std::make_shared<boost::asio::io_context::work>(io_)), + io_thread_(std::bind(&malicious_data::io_run, this)) {} +protected: + + void TearDown() { + work_.reset(); + io_thread_.join(); + io_.stop(); + } + + void io_run() { + io_.run(); + } + + boost::asio::io_context io_; + std::shared_ptr<boost::asio::io_context::work> work_; + std::thread io_thread_; +}; + +TEST_F(malicious_data, send_malicious_events) +{ + std::promise<bool> client_subscribed; + + boost::asio::ip::tcp::socket tcp_socket(io_); + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + std::thread receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::function<void()> receive; + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + const std::function<void(const boost::system::error_code&, std::size_t)> receive_cbk = [&]( + const boost::system::error_code& error, std::size_t bytes_transferred) { + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + client_subscribed.set_value(true); + keep_receiving = false; + } + } + } + + + }; + + receive = [&]() { + udp_socket.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + receive(); + while(keep_receiving) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + std::thread send_thread([&]() { + try { + std::promise<bool> client_connected; + boost::asio::ip::tcp::socket::endpoint_type local( + boost::asio::ip::address::from_string(std::string(local_address)), + 40001); + boost::asio::ip::tcp::acceptor its_acceptor(io_); + boost::system::error_code ec; + its_acceptor.open(local.protocol(), ec); + boost::asio::detail::throw_error(ec, "acceptor open"); + its_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "acceptor set_option"); + its_acceptor.bind(local, ec); + boost::asio::detail::throw_error(ec, "acceptor bind"); + its_acceptor.listen(boost::asio::socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec, "acceptor listen"); + its_acceptor.async_accept(tcp_socket, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_connected.set_value(true); + } else { + ADD_FAILURE() << "accept_cbk: " << _error.message(); + } + }); + + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x06, 0x9c, 0x41, + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client established TCP connection + if (std::future_status::timeout == client_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't connect within time"; + } + + // wait until client subscribed + if (std::future_status::timeout == client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // send malicious data as server + std::uint8_t its_malicious_data[] = { + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x38, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x86, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xad, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xd4, 0x8f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xfb, 0x9f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x22, 0xaf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, // payload missing + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0xbf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x70, 0xcf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x45, 0x22, 0x80, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x97, 0xdf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x23, 0x99, 0x00, 0x4e, 0xb3, 0xe4, 0x4e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x22, 0x91, 0x00, 0x4e, 0xb3, 0xe3, 0xd7, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x48, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x21, 0x6c, 0x00, 0x4e, 0xb3, 0xe3, 0x55, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x20, 0x00, 0x44, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x20, 0xa9, 0x00, 0x4e, 0xb3, 0xe3, 0x56, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x34, 0x1f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1f, 0xc6, 0x00, 0x4e, 0xb3, 0xe3, 0x87, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x5b, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1e, 0xf1, 0x00, 0x4e, 0xb3, 0xe3, 0x5e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x82, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xad, 0x00, 0x4e, 0xb3, 0xe3, 0xa8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa9, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xec, 0x00, 0x4e, 0xb3, 0xe3, 0xd8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, 0xc0, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xd0, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xfa, 0x00, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x19, 0x20, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x80, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1e, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x09, 0x80, 0x00, 0x44, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + tcp_socket.send(boost::asio::buffer(its_malicious_data)); + + // establish second tcp connection as client and send malicious data as well + boost::asio::ip::tcp::socket tcp_socket2(io_); + boost::asio::ip::tcp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 40001); + tcp_socket2.open(remote.protocol()); + tcp_socket2.connect(remote); + std::uint8_t its_malicious_client_data[] = { + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x38, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x5f, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x86, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xad, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xd4, 0x8f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xfb, 0x9f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x22, 0xaf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, // payload missing + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0xbf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x24, 0x02, 0x00, 0x4e, 0xb3, 0xe4, 0x7a, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x70, 0xcf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x45, 0x22, 0x80, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x97, 0xdf, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x23, 0x99, 0x00, 0x4e, 0xb3, 0xe4, 0x4e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x22, 0x91, 0x00, 0x4e, 0xb3, 0xe3, 0xd7, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x48, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x21, 0x6c, 0x00, 0x4e, 0xb3, 0xe3, 0x55, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x20, 0x00, 0x44, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x20, 0xa9, 0x00, 0x4e, 0xb3, 0xe3, 0x56, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x45, 0x6d, 0x80, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x34, 0x1f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1f, 0xc6, 0x00, 0x4e, 0xb3, 0xe3, 0x87, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x96, 0x00, 0x00, 0x45, 0x83, 0x40, 0x00, 0x44, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x5b, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1e, 0xf1, 0x00, 0x4e, 0xb3, 0xe3, 0x5e, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x45, 0x9c, 0x40, 0x00, 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x82, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xad, 0x00, 0x4e, 0xb3, 0xe3, 0xa8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x45, 0x16, 0x00, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa9, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xec, 0x00, 0x4e, 0xb3, 0xe3, 0xd8, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, 0xc0, 0x00, 0x44, 0xaf, 0x00, 0x00, 0x45, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xd0, 0x5f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xfa, 0x00, 0x00, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x19, 0x20, 0x00, 0x43, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x45, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1e, 0x7f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x05, 0x26, 0x5c, 0x00, 0x04, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x0e, 0x47, 0x36, 0x37, 0x38, 0x35, 0x37, 0x35, 0x00, 0x4d, 0xd5, 0x1d, 0xf9, 0x00, 0x4e, 0xb3, 0xe3, 0xdd, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x09, 0x80, 0x00, 0x44, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + tcp_socket2.send(boost::asio::buffer(its_malicious_client_data)); + + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); + tcp_socket.close(ec); + +} + +/* + * @test Send a message with an invalid protocol version to the test master + * two times as client and two time as service. Ensure that message with the + * WRONG_PROTOCOL_VERSION is sent back in both cases and that the client + * reestablishes the TCP connection after the service sent an message with an + * invalid protocol version back + */ +TEST_F(malicious_data, send_wrong_protocol_version) +{ + std::promise<void> remote_client_subscribed; + std::promise<void> offer_received; + + boost::asio::ip::tcp::socket tcp_socket(io_); + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + std::thread sd_receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::atomic<bool> service_offered(false); + std::atomic<bool> client_subscribed(false); + + // join the sd multicast group 224.0.24.1 + udp_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.24.1").to_v4())); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + remote_client_subscribed.set_value(); + client_subscribed = true; + } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(2,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id + 1u, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(2u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) { + std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e); + EXPECT_EQ(0u, its_casted_entry->get_minor_version()); + } + offer_received.set_value(); + service_offered = true; + } + } + if (service_offered && client_subscribed) { + keep_receiving = false; + } + } else { + ADD_FAILURE() << " received non-sd message"; + } + } + } + }); + + std::thread send_thread([&]() { + try { + std::promise<void> client_connected; + boost::asio::ip::tcp::socket::endpoint_type local( + boost::asio::ip::address::from_string(std::string(local_address)), + 40001); + boost::asio::ip::tcp::acceptor its_acceptor(io_); + boost::system::error_code ec; + its_acceptor.open(local.protocol(), ec); + boost::asio::detail::throw_error(ec, "acceptor open"); + its_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "acceptor set_option"); + its_acceptor.bind(local, ec); + boost::asio::detail::throw_error(ec, "acceptor bind"); + its_acceptor.listen(boost::asio::socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec, "acceptor listen"); + its_acceptor.async_accept(tcp_socket, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_connected.set_value(); + } else { + ADD_FAILURE() << "accept_cbk: " << _error.message(); + } + }); + + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x06, 0x9c, 0x41, + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client established TCP connection + if (std::future_status::timeout == client_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't connect within time"; + } + + // wait until client subscribed + if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // wait until a offer was received + if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive offer within time"; + } + + std::atomic<std::uint32_t> fin_as_service_received(0); + std::promise<void> client_reconnected1; + + std::thread tcp_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + + while (keep_receiving) { + boost::system::error_code error; + tcp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error == boost::asio::error::eof) { + EXPECT_EQ(boost::asio::error::eof, error); + fin_as_service_received++; + keep_receiving = false; + } else { + keep_receiving = false; + ADD_FAILURE() << __func__ << ":" << __LINE__ << " error: " << error.message(); + return; + } + } + }); + + boost::asio::ip::tcp::socket tcp_socket3(io_); + its_acceptor.async_accept(tcp_socket3, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket3.set_option(boost::asio::ip::tcp::no_delay(true)); + client_reconnected1.set_value(); + } else { + ADD_FAILURE() << "accept_cbk2: " << _error.message(); + } + }); + // send malicious data as server (too long length and wrong protocol version) + std::uint8_t its_malicious_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xBB, 0xBB, 0xCA, 0xFE, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + tcp_socket.send(boost::asio::buffer(its_malicious_data)); + + // wait until client reestablished TCP connection + if (std::future_status::timeout == client_reconnected1.get_future().wait_for(std::chrono::seconds(10))) { + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + ADD_FAILURE() << "Client didn't reconnect within time 1"; + } + + tcp_receive_thread.join(); + + EXPECT_EQ(1u, fin_as_service_received); + + std::thread tcp_receive_thread2([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + while (keep_receiving) { + boost::system::error_code error; + tcp_socket3.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error == boost::asio::error::eof) { + EXPECT_EQ(boost::asio::error::eof, error); + fin_as_service_received++; + // client must sent back error response before closing the connection + EXPECT_EQ(2u, fin_as_service_received); + if (fin_as_service_received == 2) { + keep_receiving = false; + } + } else { + keep_receiving = false; + return; + } + } + }); + + // send malicious data as server (wrong protocol version) + std::uint8_t its_malicious_data_correct_length[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xBB, 0xBB, 0xCA, 0xFE, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + tcp_socket3.send(boost::asio::buffer(its_malicious_data_correct_length)); + + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + + + tcp_receive_thread2.join(); + EXPECT_EQ(2u, fin_as_service_received); + + // establish second tcp connection as client and send malicious data as well + std::atomic<std::uint32_t> error_response_as_client_received(0); + std::atomic<std::uint32_t> fin_as_client_received(0); + + boost::asio::ip::tcp::socket tcp_socket2(io_); + boost::asio::ip::tcp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 40001); + tcp_socket2.open(remote.protocol()); + tcp_socket2.connect(remote); + + + std::thread tcp_service_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = tcp_socket2.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (!error) { + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + std::shared_ptr<vsomeip::message> its_message(its_deserializer.deserialize_message()); + EXPECT_EQ(0x3345, its_message->get_service()); + EXPECT_EQ(0x1, its_message->get_method()); + EXPECT_EQ(0xCCCC, its_message->get_client()); + EXPECT_EQ(0xDDDD, its_message->get_session()); + EXPECT_EQ(vsomeip::return_code_e::E_WRONG_PROTOCOL_VERSION, its_message->get_return_code()); + EXPECT_EQ(vsomeip::message_type_e::MT_ERROR, its_message->get_message_type()); + error_response_as_client_received++; + // service must sent back error response before closing the connection + EXPECT_EQ(error_response_as_client_received - 1u, fin_as_client_received); + } else { + EXPECT_EQ(boost::asio::error::eof, error); + fin_as_client_received++; + // service must sent back error response before closing the connection + EXPECT_EQ(error_response_as_client_received, fin_as_client_received); + if (fin_as_client_received == 1) { + keep_receiving = false; + } + } + } + }); + + // send malicious data as client (too long length and wrong protocol version) + std::uint8_t its_malicious_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xCC, 0xCC, 0xDD, 0xDD, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + tcp_socket2.send(boost::asio::buffer(its_malicious_client_data)); + tcp_service_receive_thread.join(); + EXPECT_EQ(1u, error_response_as_client_received); + EXPECT_EQ(1u, fin_as_client_received); + + tcp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket2.close(ec); + + // establish a tcp connection as client again and send wrong protocol + // version in message with a correct length field + boost::asio::ip::tcp::socket tcp_socket5(io_); + tcp_socket5.open(remote.protocol()); + tcp_socket5.connect(remote); + + std::thread tcp_service_receive_thread2([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = tcp_socket5.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (!error) { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + std::shared_ptr<vsomeip::message> its_message(its_deserializer.deserialize_message()); + EXPECT_EQ(0x3345, its_message->get_service()); + EXPECT_EQ(0x1, its_message->get_method()); + EXPECT_EQ(0xCCCC, its_message->get_client()); + EXPECT_EQ(0xDDDD, its_message->get_session()); + EXPECT_EQ(vsomeip::return_code_e::E_WRONG_PROTOCOL_VERSION, its_message->get_return_code()); + EXPECT_EQ(vsomeip::message_type_e::MT_ERROR, its_message->get_message_type()); + error_response_as_client_received++; + // service must sent back error response before closing the connection + EXPECT_EQ(error_response_as_client_received - 1u, fin_as_client_received); + if (error_response_as_client_received == 2) { + keep_receiving = false; + } + } + } + }); + + // send malicious data as client (wrong protocol version) + std::uint8_t its_malicious_client_data_correct_length[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xDD, 0xDD, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + tcp_socket5.send(boost::asio::buffer(its_malicious_client_data_correct_length)); + tcp_service_receive_thread2.join(); + EXPECT_EQ(2u, error_response_as_client_received); + EXPECT_EQ(1u, fin_as_client_received); + + tcp_socket5.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket5.close(ec); + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4()); + udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service); + udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket2.close(ec); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + + }); + + send_thread.join(); + sd_receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); + tcp_socket.close(ec); + +} + +/* + * @test Send a message with an invalid message type to the test master + * one time as client and one time as service. Ensure that the client + * reestablishes the TCP connection after the service sent an message with an + * invalid protocol version back + */ +TEST_F(malicious_data, send_wrong_message_type) +{ + std::promise<void> remote_client_subscribed; + std::promise<void> offer_received; + + boost::asio::ip::tcp::socket tcp_socket(io_); + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + std::thread sd_receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::atomic<bool> service_offered(false); + std::atomic<bool> client_subscribed(false); + + // join the sd multicast group 224.0.24.1 + udp_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.24.1").to_v4())); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + remote_client_subscribed.set_value(); + client_subscribed = true; + } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(2,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id + 1u, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(2u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) { + std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e); + EXPECT_EQ(0u, its_casted_entry->get_minor_version()); + } + offer_received.set_value(); + service_offered = true; + } + } + if (service_offered && client_subscribed) { + keep_receiving = false; + } + } else { + ADD_FAILURE() << " received non-sd message"; + } + } + } + }); + + std::thread send_thread([&]() { + try { + std::promise<void> client_connected; + boost::asio::ip::tcp::socket::endpoint_type local( + boost::asio::ip::address::from_string(std::string(local_address)), + 40001); + boost::asio::ip::tcp::acceptor its_acceptor(io_); + boost::system::error_code ec; + its_acceptor.open(local.protocol(), ec); + boost::asio::detail::throw_error(ec, "acceptor open"); + its_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "acceptor set_option"); + its_acceptor.bind(local, ec); + boost::asio::detail::throw_error(ec, "acceptor bind"); + its_acceptor.listen(boost::asio::socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec, "acceptor listen"); + its_acceptor.async_accept(tcp_socket, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_connected.set_value(); + } else { + ADD_FAILURE() << "accept_cbk: " << _error.message(); + } + }); + + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x06, 0x9c, 0x41, + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client established TCP connection + if (std::future_status::timeout == client_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't connect within time"; + } + + // wait until client subscribed + if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // wait until a offer was received + if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive offer within time"; + } + + std::atomic<bool> fin_as_service_received(false); + std::promise<void> client_reconnected; + + std::thread tcp_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + + while (keep_receiving) { + boost::system::error_code error; + tcp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (!error) { + ADD_FAILURE() << __func__ << ":" << __LINE__ + << " received a non-error:" << error.message(); + } else if (error == boost::asio::error::eof) { + EXPECT_EQ(boost::asio::error::eof, error); + fin_as_service_received = true; + keep_receiving = false; + } else { + keep_receiving = false; + ADD_FAILURE() << __func__ << ":" << __LINE__ << " error: " << error.message(); + return; + } + } + }); + + boost::asio::ip::tcp::socket tcp_socket3(io_); + its_acceptor.async_accept(tcp_socket3, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_reconnected.set_value(); + } else { + ADD_FAILURE() << "accept_cbk2: " << _error.message(); + } + }); + // send malicious data as server (too long length and wrong message type) + std::uint8_t its_malicious_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xBB, 0xBB, 0xCA, 0xFE, + 0x01, 0x00, 0xAA, 0x00 // message type set to 0xAA + }; + tcp_socket.send(boost::asio::buffer(its_malicious_data)); + + // wait until client reestablished TCP connection + if (std::future_status::timeout == client_reconnected.get_future().wait_for(std::chrono::seconds(10))) { + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + ADD_FAILURE() << "Client didn't reconnect within time"; + } else { + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + } + + tcp_receive_thread.join(); + + EXPECT_TRUE(fin_as_service_received); + + + // establish second tcp connection as client and send malicious data as well + std::atomic<bool> fin_as_client_received(false); + + boost::asio::ip::tcp::socket tcp_socket2(io_); + boost::asio::ip::tcp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 40001); + tcp_socket2.open(remote.protocol()); + tcp_socket2.connect(remote); + + + std::thread tcp_service_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::function<void()> receive; + std::vector<std::uint8_t> receive_buffer(4096); + + auto receive_cbk = [&](const boost::system::error_code& _error, + std::size_t bytes_transferred) { + (void)bytes_transferred; + if (!_error) { + ADD_FAILURE() << __func__ << ":" << __LINE__ + << " received a non-error:" << _error.message(); + } else { + EXPECT_EQ(boost::asio::error::eof, _error); + fin_as_client_received = true; + keep_receiving = false; + + } + }; + + receive = [&]() { + tcp_socket2.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + while (keep_receiving) { + receive(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + // send malicious data as client (too long length and wrong message type) + std::uint8_t its_malicious_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xCC, 0xCC, 0xDD, 0xDD, + 0x01, 0x00, 0xAA, 0x00 // protocol version set to 0xAA + }; + tcp_socket2.send(boost::asio::buffer(its_malicious_client_data)); + tcp_service_receive_thread.join(); + EXPECT_TRUE(fin_as_client_received); + + tcp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket2.close(ec); + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4()); + udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service); + udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket2.close(ec); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + + }); + + send_thread.join(); + sd_receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); + tcp_socket.close(ec); + +} + +/* + * @test Send a message with an invalid return code to the test master + * one time as client and one time as service. Ensure that the client + * reestablishes the TCP connection after the service sent an message with an + * invalid protocol version back + */ +TEST_F(malicious_data, send_wrong_return_code) +{ + std::promise<void> remote_client_subscribed; + std::promise<void> offer_received; + + boost::asio::ip::tcp::socket tcp_socket(io_); + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + std::thread sd_receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::atomic<bool> service_offered(false); + std::atomic<bool> client_subscribed(false); + + // join the sd multicast group 224.0.24.1 + udp_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.24.1").to_v4())); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + remote_client_subscribed.set_value(); + client_subscribed = true; + } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(2,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id + 1u, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(2u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) { + std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e); + EXPECT_EQ(0u, its_casted_entry->get_minor_version()); + } + offer_received.set_value(); + service_offered = true; + } + } + if (service_offered && client_subscribed) { + keep_receiving = false; + } + } else { + ADD_FAILURE() << " received non-sd message"; + } + } + } + }); + + std::thread send_thread([&]() { + try { + std::promise<void> client_connected; + boost::asio::ip::tcp::socket::endpoint_type local( + boost::asio::ip::address::from_string(std::string(local_address)), + 40001); + boost::asio::ip::tcp::acceptor its_acceptor(io_); + boost::system::error_code ec; + its_acceptor.open(local.protocol(), ec); + boost::asio::detail::throw_error(ec, "acceptor open"); + its_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "acceptor set_option"); + its_acceptor.bind(local, ec); + boost::asio::detail::throw_error(ec, "acceptor bind"); + its_acceptor.listen(boost::asio::socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec, "acceptor listen"); + its_acceptor.async_accept(tcp_socket, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_connected.set_value(); + } else { + ADD_FAILURE() << "accept_cbk: " << _error.message(); + } + }); + + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x06, 0x9c, 0x41, + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client established TCP connection + if (std::future_status::timeout == client_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't connect within time"; + } + + // wait until client subscribed + if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // wait until a offer was received + if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive offer within time"; + } + + std::atomic<bool> fin_as_service_received(false); + std::promise<void> client_reconnected; + + std::thread tcp_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + + while (keep_receiving) { + boost::system::error_code error; + tcp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (!error) { + ADD_FAILURE() << __func__ << ":" << __LINE__ + << " received a non-error:" << error.message(); + } else if (error == boost::asio::error::eof) { + EXPECT_EQ(boost::asio::error::eof, error); + fin_as_service_received = true; + keep_receiving = false; + } else { + keep_receiving = false; + ADD_FAILURE() << __func__ << ":" << __LINE__ << " error: " << error.message(); + return; + } + } + }); + + boost::asio::ip::tcp::socket tcp_socket3(io_); + its_acceptor.async_accept(tcp_socket3, [&](boost::system::error_code _error) { + if (!_error) { + // Nagle algorithm off + tcp_socket.set_option(boost::asio::ip::tcp::no_delay(true)); + client_reconnected.set_value(); + } else { + ADD_FAILURE() << "accept_cbk2: " << _error.message(); + } + }); + // send malicious data as server (too long length and wrong return code) + std::uint8_t its_malicious_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xBB, 0xBB, 0xCA, 0xFE, + 0x01, 0x00, 0x00, 0xAA // return code set to 0xAA + }; + tcp_socket.send(boost::asio::buffer(its_malicious_data)); + + // wait until client reestablished TCP connection + if (std::future_status::timeout == client_reconnected.get_future().wait_for(std::chrono::seconds(10))) { + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + ADD_FAILURE() << "Client didn't reconnect within time"; + } else { + tcp_socket3.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket3.close(ec); + } + + tcp_receive_thread.join(); + + EXPECT_TRUE(fin_as_service_received); + + + // establish second tcp connection as client and send malicious data as well + std::atomic<bool> fin_as_client_received(false); + + boost::asio::ip::tcp::socket tcp_socket2(io_); + boost::asio::ip::tcp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 40001); + tcp_socket2.open(remote.protocol()); + tcp_socket2.connect(remote); + + + std::thread tcp_service_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::function<void()> receive; + std::vector<std::uint8_t> receive_buffer(4096); + + auto receive_cbk = [&](const boost::system::error_code& _error, + std::size_t bytes_transferred) { + (void)bytes_transferred; + if (!_error) { + ADD_FAILURE() << __func__ << ":" << __LINE__ + << " received a non-error:" << _error.message(); + } else { + EXPECT_EQ(boost::asio::error::eof, _error); + fin_as_client_received = true; + keep_receiving = false; + + } + }; + + receive = [&]() { + tcp_socket2.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + while (keep_receiving) { + receive(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + // send malicious data as client (too long length and wrong return code) + std::uint8_t its_malicious_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x7f, + 0xCC, 0xCC, 0xDD, 0xDD, + 0x01, 0x00, 0x00, 0xAA // return version set to 0xAA + }; + tcp_socket2.send(boost::asio::buffer(its_malicious_client_data)); + tcp_service_receive_thread.join(); + EXPECT_TRUE(fin_as_client_received); + + tcp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket2.close(ec); + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4()); + udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service); + udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket2.close(ec); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + + }); + + send_thread.join(); + sd_receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); + tcp_socket.close(ec); + +} + +/* + * @test Send a message with an invalid protocol version, invalid message type + * and invalid return code via UDP to the test master + * one time as client and one time as service. Ensure that message with the + * WRONG_PROTOCOL_VERSION is sent back in both cases + */ +TEST_F(malicious_data, wrong_header_fields_udp) +{ + std::promise<void> remote_client_subscribed; + std::promise<void> offer_received; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + boost::asio::ip::udp::socket udp_socket_service(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 40001)); + + boost::asio::ip::udp::endpoint udp_client_info; + boost::asio::ip::udp::endpoint udp_service_info; + + + std::thread sd_receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::atomic<bool> service_offered(false); + std::atomic<bool> client_subscribed(false); + + // join the sd multicast group 224.0.24.1 + udp_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.24.1").to_v4())); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(1u, its_casted_entry->get_eventgroup()); + } + std::shared_ptr<vsomeip::sd::option_impl> op = sd_msg.get_options().front(); + EXPECT_EQ(op->get_type(), vsomeip::sd::option_type_e::IP4_ENDPOINT); + EXPECT_EQ(op->get_length(), 9u); + if (op->get_type() == vsomeip::sd::option_type_e::IP4_ENDPOINT) { + std::shared_ptr<vsomeip::sd::ipv4_option_impl> ip_op + = std::static_pointer_cast<vsomeip::sd::ipv4_option_impl>(op); + EXPECT_EQ(vsomeip::sd::layer_four_protocol_e::UDP, ip_op->get_layer_four_protocol()); + udp_client_info = boost::asio::ip::udp::endpoint( + boost::asio::ip::address_v4(ip_op->get_address()), + ip_op->get_port()); + } + + remote_client_subscribed.set_value(); + client_subscribed = true; + } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(2,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(malicious_data_test::service.service_id + 1u, e->get_service()); + EXPECT_EQ(malicious_data_test::service.instance_id, e->get_instance()); + EXPECT_EQ(2u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) { + std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e); + EXPECT_EQ(0u, its_casted_entry->get_minor_version()); + } + for (const auto& op : sd_msg.get_options()) { + EXPECT_EQ(op->get_type(), vsomeip::sd::option_type_e::IP4_ENDPOINT); + EXPECT_EQ(op->get_length(), 9u); + if (op->get_type() == vsomeip::sd::option_type_e::IP4_ENDPOINT) { + std::shared_ptr<vsomeip::sd::ipv4_option_impl> ip_op + = std::static_pointer_cast<vsomeip::sd::ipv4_option_impl>(op); + if (ip_op->get_layer_four_protocol() == vsomeip::sd::layer_four_protocol_e::UDP) { + EXPECT_EQ(vsomeip::sd::layer_four_protocol_e::UDP, ip_op->get_layer_four_protocol()); + udp_service_info = boost::asio::ip::udp::endpoint( + boost::asio::ip::address_v4(ip_op->get_address()), + ip_op->get_port()); + } + } + } + offer_received.set_value(); + service_offered = true; + } + } + if (service_offered && client_subscribed) { + keep_receiving = false; + } + } else { + ADD_FAILURE() << " received non-sd message"; + } + } + } + }); + + std::thread send_thread([&]() { + try { + boost::system::error_code ec; + udp_socket_service.set_option(boost::asio::socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "udp_socket_service set_option"); + + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x33, 0x44, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x11, 0x9c, 0x41, // offer via udp + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_offer_service_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + + // wait until client subscribed + if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + } + + // wait until a offer was received + if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive offer within time"; + } + + // send malicious data as server (wrong protocol version) + std::uint8_t wrong_protocol_data[] = { + 0x33, 0x44, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xAA, 0xAA, 0xCA, 0xFE, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + udp_socket_service.send_to(boost::asio::buffer(wrong_protocol_data), udp_client_info); + + std::uint8_t wrong_message_type_data[] = { + 0x33, 0x44, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xBB, 0xBB, 0xCA, 0xFE, + 0x01, 0x00, 0xBB, 0x00 // message type set to 0xBB + }; + udp_socket_service.send_to(boost::asio::buffer(wrong_message_type_data), udp_client_info); + + std::uint8_t wrong_return_code_data[] = { + 0x33, 0x44, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xCA, 0xFE, + 0x01, 0x00, 0x00, 0xCC // return code set to 0xCC + }; + udp_socket_service.send_to(boost::asio::buffer(wrong_return_code_data), udp_client_info); + + std::uint8_t all_wrong_data[] = { + 0x33, 0x44, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xAA, 0xAA, 0xCA, 0xFE, + 0xAA, 0x00, 0xBB, 0xCC + }; + udp_socket_service.send_to(boost::asio::buffer(all_wrong_data), udp_client_info); + + udp_socket_service.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket_service.close(ec); + + // establish second UDP connection as client and send malicious data as well + std::atomic<bool> error_response_as_client_received(false); + + boost::asio::ip::udp::socket udp_socket_client(io_); + boost::asio::ip::udp::socket::endpoint_type remote( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket_client.open(remote.protocol()); + udp_socket_client.connect(remote); + + + std::thread udp_client_receive_thread([&]() { + std::atomic<bool> keep_receiving(true); + std::function<void()> receive; + std::vector<std::uint8_t> receive_buffer(4096); + + auto receive_cbk = [&](const boost::system::error_code& _error, + std::size_t bytes_transferred) { + if (!_error) { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + std::shared_ptr<vsomeip::message> its_message(its_deserializer.deserialize_message()); + EXPECT_EQ(0x3345, its_message->get_service()); + EXPECT_EQ(0x1, its_message->get_method()); + EXPECT_EQ(0xCCCC, its_message->get_client()); + EXPECT_EQ(0xDDDD, its_message->get_session()); + EXPECT_EQ(vsomeip::return_code_e::E_WRONG_PROTOCOL_VERSION, its_message->get_return_code()); + EXPECT_EQ(vsomeip::message_type_e::MT_ERROR, its_message->get_message_type()); + error_response_as_client_received = true; + keep_receiving = false; + } else { + ADD_FAILURE() << __func__ << ":" << __LINE__ << " error: " << _error.message(); + return; + } + }; + + receive = [&]() { + udp_socket_client.async_receive(boost::asio::buffer(receive_buffer, receive_buffer.capacity()), + receive_cbk); + }; + + while (keep_receiving) { + receive(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + + // send malicious data as client (too long length and wrong protocol version) + std::uint8_t wrong_protocol_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xDD, 0xDD, + 0xAA, 0x00, 0x00, 0x00 // protocol version set to 0xAA + }; + udp_socket_client.send_to(boost::asio::buffer(wrong_protocol_client_data), udp_service_info); + + std::uint8_t wrong_message_type_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xDD, 0xDD, + 0x01, 0x00, 0xBB, 0x00 // message type set to 0xBB + }; + udp_socket_client.send_to(boost::asio::buffer(wrong_message_type_client_data), udp_service_info); + + std::uint8_t wrong_return_code_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xDD, 0xDD, + 0x01, 0x00, 0x00, 0xCC // return code set to 0xCC + }; + udp_socket_client.send_to(boost::asio::buffer(wrong_return_code_client_data), udp_service_info); + + std::uint8_t all_wrong_client_data[] = { + 0x33, 0x45, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xCC, 0xCC, 0xDD, 0xDD, + 0xAA, 0x00, 0xBB, 0xCC + }; + udp_socket_client.send_to(boost::asio::buffer(all_wrong_client_data), udp_service_info); + + + udp_client_receive_thread.join(); + EXPECT_TRUE(error_response_as_client_received); + + udp_socket_client.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket_client.close(ec); + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x33, 0x45, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4()); + udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service); + udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket2.close(ec); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + + }); + + send_thread.join(); + sd_receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 3) { + std::cerr << "Please pass an target, local IP address and test mode to this binary like: " + << argv[0] << " 10.0.3.1 10.0.3.202 EVENTS" << std::endl; + exit(1); + } + remote_address = argv[1]; + local_address = argv[2]; + std::string its_testmode = argv[3]; + if (its_testmode == std::string("MALICIOUS_EVENTS")) { + ::testing::GTEST_FLAG(filter) = "*send_malicious_events"; + } else if (its_testmode == std::string("PROTOCOL_VERSION")) { + ::testing::GTEST_FLAG(filter) = "*send_wrong_protocol_version"; + } else if (its_testmode == std::string("MESSAGE_TYPE")) { + ::testing::GTEST_FLAG(filter) = "*send_wrong_message_type"; + } else if (its_testmode == std::string("RETURN_CODE")) { + ::testing::GTEST_FLAG(filter) = "*send_wrong_return_code"; + } else if (its_testmode == std::string("WRONG_HEADER_FIELDS_UDP")) { + ::testing::GTEST_FLAG(filter) = "*wrong_header_fields_udp"; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_service.cpp new file mode 100644 index 00000000000..56538aec1eb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/malicious_data_tests/malicious_data_test_service.cpp @@ -0,0 +1,188 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "malicious_data_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class malicious_data_test_service : public vsomeip_utilities::base_logger { +public: + malicious_data_test_service(struct malicious_data_test::service_info _service_info, malicious_data_test::test_mode_e _testmode) : + vsomeip_utilities::base_logger("MDTS", "MALICIOUS DATA TEST SERVICE"), + service_info_(_service_info), + testmode_(_testmode), + app_(vsomeip::runtime::get()->create_application("malicious_data_test_service")), + wait_until_registered_(true), + wait_until_shutdown_method_called_(true), + received_events_(0), + received_methodcalls_(0), + offer_thread_(std::bind(&malicious_data_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&malicious_data_test_service::on_state, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(_service_info.eventgroup_id); + app_->request_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, vsomeip::event_type_e::ET_EVENT, + vsomeip::reliability_type_e::RT_UNKNOWN); + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&malicious_data_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + std::bind(&malicious_data_test_service::on_event, this, + std::placeholders::_1)); + + app_->register_message_handler(static_cast<vsomeip::service_t>(service_info_.service_id + 1u), + service_info_.instance_id, 0x1, + std::bind(&malicious_data_test_service::on_message, this, + std::placeholders::_1)); + + // request service of client + app_->request_service(service_info_.service_id, service_info_.instance_id); + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.eventgroup_id, 0, + service_info_.event_id); + + app_->start(); + } + + ~malicious_data_test_service() { + if (testmode_ == malicious_data_test::test_mode_e::MALICIOUS_EVENTS) { + EXPECT_EQ(9u, received_events_); + EXPECT_EQ(9u, received_methodcalls_); + } + offer_thread_.join(); + } + + void offer() { + app_->offer_service(static_cast<vsomeip::service_t>(service_info_.service_id + 1u), 0x1); + } + + void stop() { + app_->stop_offer_service(static_cast<vsomeip::service_t>(service_info_.service_id + 1u), 0x1); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_event(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.event_id, _message->get_method()); + EXPECT_EQ(std::uint32_t(0x7F), _message->get_length()); + received_events_++; + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(static_cast<vsomeip::service_t>(service_info_.service_id + 1u), _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(vsomeip::method_t(0x1), _message->get_method()); + EXPECT_EQ(std::uint32_t(0x7F), _message->get_length()); + received_methodcalls_++; + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + stop(); + } + +private: + struct malicious_data_test::service_info service_info_; + malicious_data_test::test_mode_e testmode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_shutdown_method_called_; + std::uint32_t received_events_; + std::uint32_t received_methodcalls_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; +}; + +malicious_data_test::test_mode_e its_testmode(malicious_data_test::test_mode_e::MALICIOUS_EVENTS); + +TEST(someip_malicious_data_test, block_subscription_handler) +{ + malicious_data_test_service its_sample(malicious_data_test::service, its_testmode); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + std::string its_passed_testmode = argv[1]; + if (its_passed_testmode == std::string("MALICIOUS_EVENTS")) { + its_testmode = malicious_data_test::test_mode_e::MALICIOUS_EVENTS; + } else if (its_passed_testmode == std::string("PROTOCOL_VERSION")) { + its_testmode = malicious_data_test::test_mode_e::PROTOCOL_VERSION; + } else if (its_passed_testmode == std::string("MESSAGE_TYPE")) { + its_testmode = malicious_data_test::test_mode_e::MESSAGE_TYPE; + } else if (its_passed_testmode == std::string("RETURN_CODE")) { + its_testmode = malicious_data_test::test_mode_e::RETURN_CODE; + } else if (its_passed_testmode == std::string("WRONG_HEADER_FIELDS_UDP")) { + its_testmode = malicious_data_test::test_mode_e::WRONG_HEADER_FIELDS_UDP; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/CMakeLists.txt new file mode 100644 index 00000000000..9a3f8c06892 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(memory_tests LANGUAGES CXX) + +# Configure necessary files into the build directory. +set(configuration_files + memory_test_client.json + memory_test_master_starter.sh + memory_test_service.json + memory_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(memory_test_client + memory_test_client.cpp +) + +# Add test executable. +add_executable(memory_test_service + memory_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + memory_test_service + memory_test_client +) +targets_link_default_libraries("${executables}") +targets_add_default_dependencies("${executables}") + +# Add custom test command. +add_custom_test( + NAME memory_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/memory_test_master_starter.sh + TIMEOUT 600 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_client.json.in new file mode 100644 index 00000000000..0964655f2cf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_client.json.in @@ -0,0 +1,37 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging": { + "level": "verbose", + "console": "true", + "file": { + "enable": "true", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "tracing" : + { + "enable" : "false" + } +, + "services" : + [ + { + "service" : "0xb519", + "instance" : "0x0001", + "unicast" : "@TEST_IP_SLAVE@", + "unreliable" : "30503", + "someip-tp" : { + "client-to-service": [ "0x8008", "0x8009", "0x800a", "0x800b", "0x800c", "0x800d", "0x800e", "0x800f", "0x8010", "0x8011", "0x8012", "0x8013", "0x8014", "0x8015", "0x8016", "0x8017", "0x8018", "0x8019", "0x801a", "0x801b"] + } + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_master_starter.sh.in new file mode 100755 index 00000000000..f0c57e4f9e7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_master_starter.sh.in @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=memory_test_client.json + +./memory_test_client & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting memory test on slave LXC memory_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/memory_tests; ./memory_test_slave_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./memory_test_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** memory_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** memory_test_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +sleep 3 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_service.json.in new file mode 100644 index 00000000000..e8903937d75 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_service.json.in @@ -0,0 +1,35 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging": { + "level": "verbose", + "console": "true", + "file": { + "enable": "true", + "path": "/tmp/foo.log" + }, + "dlt": "true" + }, + "tracing" : + { + "enable" : "false" + }, + "services" : + [ + { + "service" : "0xb519", + "instance" : "0x0001", + "unreliable" : "30503", + "someip-tp" : { + "service-to-client": [ "0x8008", "0x8009", "0x800a", "0x800b", "0x800c", "0x800d", "0x800e", "0x800f", "0x8010", "0x8011", "0x8012", "0x8013", "0x8014", "0x8015", "0x8016", "0x8017", "0x8018", "0x8019", "0x801a", "0x801b"] + } + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.251.192.252", + "port" : "30490", + "protocol" : "udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_slave_starter.sh.in new file mode 100755 index 00000000000..a543c1baf99 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/conf/memory_test_slave_starter.sh.in @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=memory_test_service.json + +./memory_test_service & +PID_SLAVE=$! + +# Wait until all slaves are finished +for job in $PID_SLAVE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.cpp new file mode 100644 index 00000000000..b2eb5869514 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.cpp @@ -0,0 +1,213 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> +#include <cstring> + +#include <vsomeip/internal/logger.hpp> +#include "memory_test_client.hpp" + +void check_memory(std::vector<std::uint64_t> &test_memory_, std::atomic<bool> &stop_checking_) +{ + while (!stop_checking_) { + std::this_thread::sleep_for(MEMORY_CHECKER_INTERVAL); + + static const std::uint32_t its_pagesize = static_cast<std::uint32_t>(getpagesize() / 1024); + + std::FILE *its_file = std::fopen("/proc/self/statm", "r"); + if (!its_file) { + VSOMEIP_ERROR << "check_memory: couldn't open:" + << std::string(std::strerror(errno)); + return; + } + std::uint64_t its_size(0); + std::uint64_t its_rsssize(0); + std::uint64_t its_sharedpages(0); + std::uint64_t its_text(0); + std::uint64_t its_lib(0); + std::uint64_t its_data(0); + std::uint64_t its_dirtypages(0); + + if (EOF + == std::fscanf(its_file, "%lu %lu %lu %lu %lu %lu %lu", &its_size, &its_rsssize, + &its_sharedpages, &its_text, &its_lib, &its_data, &its_dirtypages)) { + VSOMEIP_ERROR << "check_memory: error reading:" + << std::string(std::strerror(errno)); + } + std::fclose(its_file); + + test_memory_.push_back(its_rsssize * its_pagesize); + VSOMEIP_INFO << "logged client: "<< its_rsssize * its_pagesize; + + } +} + +// Flag the desired event availability +void memory_test_client::on_availability(vsomeip::service_t service_, vsomeip::instance_t instance_, + bool is_available_) +{ + if (is_available_ && service_ == MEMORY_SERVICE && instance_ == MEMORY_INSTANCE) { + std::unique_lock<std::mutex> lk(availability_mutex); + availability = true; + condition_availability.notify_one(); + } +} + +void memory_test_client::on_message(const std::shared_ptr<vsomeip::message> &message_) +{ + if (MEMORY_SERVICE == message_->get_service() && message_->get_method() <= MEMORY_EVENT + TEST_EVENT_NUMBER + && message_->get_method() >= MEMORY_EVENT) { + auto its_runtime = vsomeip::runtime::get(); + auto its_message = its_runtime->create_request(false); + its_message->set_service(message_->get_service()); + its_message->set_instance(message_->get_instance()); + its_message->set_method(message_->get_method()); + its_message->set_interface_version(message_->get_interface_version()); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_payload(message_->get_payload()); + _app->send(its_message); + std::lock_guard<std::mutex> lk(event_counter_mutex); + received_messages_counter++; + sec = std::chrono::system_clock::now(); + } +} + +memory_test_client::memory_test_client(const char *app_name_, const char *app_id_, + std::map<vsomeip::event_t, int> map_events_) + : vsomeip_utilities::base_vsip_app(app_name_, app_id_), map_events(map_events_) +{ + sec = std::chrono::system_clock::now(); + _app->register_availability_handler(MEMORY_SERVICE, MEMORY_INSTANCE, + std::bind(&memory_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + MEMORY_MAJOR, MEMORY_MINOR); + _app->register_message_handler( + MEMORY_SERVICE, MEMORY_INSTANCE, vsomeip::ANY_EVENT, + std::bind(&memory_test_client::on_message, this, std::placeholders::_1)); + for (uint16_t i = 0; i < TEST_EVENT_NUMBER; i++) { + _app->request_event(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENT + i, + { MEMORY_EVENTGROUP }, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + } + _app->request_service(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_MAJOR, MEMORY_MINOR); + for (uint16_t i = 0; i < TEST_EVENT_NUMBER; i++) { + _app->subscribe(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENTGROUP, MEMORY_MAJOR, + MEMORY_EVENT + i); + } +} + +void memory_test_client::send_request(std::atomic<bool> &stop_checking_) +{ + std::unique_lock<std::mutex> lk(availability_mutex); + // Only send the requests when the service availability is secured + if (condition_availability.wait_for(lk, WAIT_AVAILABILITY, + [=] { return availability; })) { + + // Trigger the test + auto its_message = vsomeip_utilities::create_standard_vsip_request( + MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_START_METHOD, MEMORY_MAJOR, + vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + _app->send(its_message); + } + + EXPECT_TRUE(availability) << "Events expected by the client were not available for 15 seconds "; + + bool stop_watchdog { false }; + + // 3. Wait for service to send all the messages + while (!stop_watchdog) { + std::this_thread::sleep_for(WATCHDOG_INTERVAL); + std::lock_guard<std::mutex> lk(event_counter_mutex); + if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - sec) + .count() + > 10) { + stop_watchdog = true; + } + } + VSOMEIP_INFO << "received " << received_messages_counter; + stop_checking_ = true; +} + +void memory_test_client::unsubscribe_all() +{ + _app->unsubscribe(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENTGROUP); +} + +void memory_test_client::stop_service() +{ + auto its_message = vsomeip_utilities::create_standard_vsip_request( + MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_STOP_METHOD, MEMORY_MAJOR, + vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + _app->send(its_message); + VSOMEIP_INFO << "sending stop " << received_messages_counter; + +} + +memory_test_client::~memory_test_client() +{ + stop_service(); + unsubscribe_all(); +} + +TEST(memory_tests, receive_messages) +{ + + // Test steps: + // 1: Start measuring memory load + // 2: Send requests for 20 different events + // 3: Wait for receiving all responses from service + // 4: Stop measuring load and evaluate load increase + // + // At the end evaluate if the threshold of 5% increase in memory load was not surpassed + + std::map<vsomeip::event_t, int> events_to_subscribe; + + for (vsomeip::event_t i = 0; i < TEST_EVENT_NUMBER; i++) { + events_to_subscribe[MEMORY_EVENT + i] = 0; + } + + memory_test_client memory_test_client("memory_tests_client", "MTC", events_to_subscribe); + + std::atomic<bool> stop_checking { false }; + + // 1. Measure load until stop_checking is triggered + std::thread memory_checker_thread; + memory_checker_thread = std::thread([&stop_checking] { + std::vector<std::uint64_t> test_memory_array; + std::uint64_t sum { 0 }; + + check_memory(test_memory_array, stop_checking); + + for (auto memory_stat : test_memory_array) { + sum += memory_stat; + VSOMEIP_INFO << memory_stat; + } + double memory_average = static_cast<double>(sum) / static_cast<double>(test_memory_array.size()); + VSOMEIP_INFO << memory_average; + + // 4. Evaluate memory load increase + for (auto memory_stat : test_memory_array) { + EXPECT_LT(static_cast<double>(memory_stat), + (static_cast<double>(memory_average) * MEMORY_LOAD_LIMIT)) + << "memory not lesser than " + << (static_cast<double>(memory_average) * MEMORY_LOAD_LIMIT); + } + }); + + // 2. Send a request and wait until all the messages are sent by the service + memory_test_client.send_request(stop_checking); + + if (memory_checker_thread.joinable()) { + memory_checker_thread.join(); + } +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.hpp new file mode 100644 index 00000000000..b2950de3731 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_client.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MEMORY_TEST_CLIENT_HPP_ +#define MEMORY_TEST_CLIENT_HPP_ + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "memory_test_common.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class memory_test_client : public vsomeip_utilities::base_vsip_app +{ +public: + memory_test_client(const char *app_name_, const char *app_id_, + std::map<vsomeip::event_t, int> map_events_); + void send_request(std::atomic<bool> &stop_checking_); + + ~memory_test_client(); + +private: + std::condition_variable condition_availability; + std::mutex availability_mutex; + std::mutex event_counter_mutex; + bool availability { false }; + int received_messages_counter { 0 }; + std::map<vsomeip::event_t, int> map_events; + std::chrono::time_point<std::chrono::system_clock> sec; + void on_availability(vsomeip::service_t service_, vsomeip::instance_t instance_, + bool is_available_); + void on_message(const std::shared_ptr<vsomeip::message> &message_); + void stop_service(); + void unsubscribe_all(); + +}; + +#endif // MEMORY_TEST_CLIENT_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_common.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_common.hpp new file mode 100644 index 00000000000..3419534e5fd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_common.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MEMORY_TEST_COMMON_HPP_ +#define MEMORY_TEST_COMMON_HPP_ + +#include <vsomeip/vsomeip.hpp> + +constexpr vsomeip::service_t MEMORY_SERVICE = 0xb519; +constexpr vsomeip::instance_t MEMORY_INSTANCE = 0x0001; +constexpr vsomeip::method_t MEMORY_START_METHOD = 0x0998; +constexpr vsomeip::method_t MEMORY_STOP_METHOD = 0x0999; +constexpr vsomeip::event_t MEMORY_EVENT = 0x8008; +constexpr vsomeip::eventgroup_t MEMORY_EVENTGROUP = 0x0005; +constexpr vsomeip::major_version_t MEMORY_MAJOR = 0x01; +constexpr vsomeip::minor_version_t MEMORY_MINOR = 0x01; + +constexpr auto MEMORY_CHECKER_INTERVAL = std::chrono::seconds(5); +constexpr auto MESSAGE_SENDER_INTERVAL = std::chrono::milliseconds(5); +constexpr auto WATCHDOG_INTERVAL = std::chrono::seconds(2); +constexpr auto WAIT_AVAILABILITY = std::chrono::milliseconds(15000); +constexpr auto WAIT_START_MESSAGE = std::chrono::milliseconds(10000); +constexpr auto WAIT_STOP_MESSAGE = std::chrono::seconds(30); + +constexpr uint16_t TEST_EVENT_NUMBER = 20; +constexpr uint16_t TEST_MESSAGE_NUMBER = 9000; +constexpr int NOTIFY_PAYLOAD_SIZE = 4000; +constexpr double MEMORY_LOAD_LIMIT = 1.15; // meaning 15% limit above the average value + +#endif // MEMORY_TEST_COMMON_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.cpp new file mode 100644 index 00000000000..f5c5f2883f8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.cpp @@ -0,0 +1,177 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/internal/logger.hpp> +#include <cstring> + +#include "memory_test_service.hpp" + +void check_memory(std::vector<std::uint64_t> &test_memory_, std::atomic<bool> &stop_checking_) +{ + while (!stop_checking_) { + std::this_thread::sleep_for(MEMORY_CHECKER_INTERVAL); + + static const std::uint32_t its_pagesize = static_cast<std::uint32_t>(getpagesize() / 1024); + + std::FILE *its_file = std::fopen("/proc/self/statm", "r"); + if (!its_file) { + VSOMEIP_ERROR << "check_memory: couldn't open:" + << std::string(std::strerror(errno)); + return; + } + std::uint64_t its_size(0); + std::uint64_t its_rsssize(0); + std::uint64_t its_sharedpages(0); + std::uint64_t its_text(0); + std::uint64_t its_lib(0); + std::uint64_t its_data(0); + std::uint64_t its_dirtypages(0); + + if (EOF + == std::fscanf(its_file, "%lu %lu %lu %lu %lu %lu %lu", &its_size, &its_rsssize, + &its_sharedpages, &its_text, &its_lib, &its_data, &its_dirtypages)) { + VSOMEIP_ERROR << "check_memory: error reading:" + << std::string(std::strerror(errno)); + } + std::fclose(its_file); + + test_memory_.push_back(its_rsssize * its_pagesize); + VSOMEIP_INFO << "logged service: "<< its_rsssize * its_pagesize; + + } +} +memory_test_service::memory_test_service(const char *app_name_, const char *app_id_) + : vsomeip_utilities::base_vsip_app(app_name_, app_id_) +{ + for (uint16_t i = 0; i < TEST_EVENT_NUMBER; i++) { + _app->offer_event(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENT + i, { MEMORY_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), false, + true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + } + _app->register_message_handler( + MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_START_METHOD, + std::bind(&memory_test_service::on_start, this, std::placeholders::_1)); + _app->register_message_handler( + MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_STOP_METHOD, + std::bind(&memory_test_service::on_stop, this, std::placeholders::_1)); + _app->offer_service(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_MAJOR, MEMORY_MINOR); +} +void memory_test_service::on_start(const std::shared_ptr<vsomeip::message> /*&_message*/) +{ + std::unique_lock<std::mutex> lk(start_mutex); + received_message = true; + condition_wait_start.notify_one(); +} + +void memory_test_service::on_stop(const std::shared_ptr<vsomeip::message> /*&_message*/) +{ + { + std::unique_lock<std::mutex> lk(stop_mutex); + condition_wait_stop.notify_one(); + } + VSOMEIP_INFO << "service: " << __func__ << ": Received a STOP command."; +} + +void memory_test_service::message_sender(std::atomic<bool> &stop_checking_) +{ + auto its_payload = vsomeip::runtime::get()->create_payload(); + auto its_payload2 = vsomeip::runtime::get()->create_payload(); + + its_payload->set_data(std::vector<uint8_t>(NOTIFY_PAYLOAD_SIZE, 20)); + its_payload2->set_data(std::vector<uint8_t>(NOTIFY_PAYLOAD_SIZE, 10)); + int count { 0 }; + for (int message_no = 0; message_no <= TEST_MESSAGE_NUMBER; message_no++) { + for (uint16_t i = 0; i < TEST_EVENT_NUMBER; i++) { + _app->notify(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENT + i, its_payload); + count++; + } + std::this_thread::sleep_for(MESSAGE_SENDER_INTERVAL); + for (uint16_t i = 0; i < TEST_EVENT_NUMBER; i++) { + _app->notify(MEMORY_SERVICE, MEMORY_INSTANCE, MEMORY_EVENT + i, its_payload2); + count++; + } + std::this_thread::sleep_for(MESSAGE_SENDER_INTERVAL); + } + stop_checking_ = true; + VSOMEIP_INFO << "sent " << count << " messages"; +} + +// wait for the start message, run the threads to send messages +// and receive the stop message in the end +void memory_test_service::setup_app(const std::function<void(void)> executionHandler_) +{ + std::unique_lock<std::mutex> lk(start_mutex); + if (condition_wait_start.wait_for(lk, WAIT_START_MESSAGE, + [=] { return received_message; })) { + + // If executionHandler_ is set / not nullptr + if (executionHandler_) { + // run send the messages + executionHandler_(); + } + + { + // 3. Wait for client to send stop message + std::unique_lock<std::mutex> lk(stop_mutex); + condition_wait_stop.wait_for(lk, WAIT_STOP_MESSAGE); + std::cout << "service: exiting" << std::endl; + } + } +} + +TEST(memory_test, send_messages) +{ + + // Test steps: + // 1: Start measuring memory load + // 2: After receiving start message from the client, start sending + // notifications (load bigger than 1392 bytes) for each event + // TP + // 3: Wait for client stop message + // 4: Stop measuring load and evaluate load increase + // + // At the end evaluate if the threshold of 5% increase in memory load was not surpassed + + memory_test_service its_service("memory_test_service", "MTS"); + std::atomic<bool> stop_checking { false }; + + std::thread memory_checker_thread; + + // 1. Measure load until stop_checking is triggered + its_service.setup_app([&] { + memory_checker_thread = std::thread([&stop_checking] { + std::vector<std::uint64_t> test_memory_array; + std::uint64_t sum { 0 }; + + check_memory(test_memory_array, stop_checking); + + for (auto memory_stat : test_memory_array) { + sum += memory_stat; + VSOMEIP_INFO << memory_stat; + } + double memory_average = static_cast<double>(sum) / static_cast<double>(test_memory_array.size()); + VSOMEIP_INFO << memory_average; + + // 4. Evaluate memory load increase + for (auto memory_stat : test_memory_array) { + EXPECT_LT(static_cast<double>(memory_stat), + (static_cast<double>(memory_average) * MEMORY_LOAD_LIMIT)) + << "memory not lesser than " + << (static_cast<double>(memory_average) * MEMORY_LOAD_LIMIT); + } + }); + // 2. Start sending notifications + its_service.message_sender(stop_checking); + }); + + if (memory_checker_thread.joinable()) { + memory_checker_thread.join(); + } +} +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.hpp new file mode 100644 index 00000000000..2c70e33a353 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/memory_tests/memory_test_service.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MEMORY_TEST_SERVICE_HPP_ +#define MEMORY_TEST_SERVICE_HPP_ + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <common/vsomeip_app_utilities.hpp> + +#include "memory_test_common.hpp" + +class memory_test_service : public vsomeip_utilities::base_vsip_app +{ +public: + memory_test_service(const char *app_name_, const char *app_id_); + void setup_app(const std::function<void(void)> executionHandler_); + void message_sender(std::atomic<bool> &stop_checking_); + +private: + std::condition_variable condition_wait_start; + std::condition_variable condition_wait_stop; + std::mutex start_mutex; + std::mutex stop_mutex; + bool received_message { false }; + + void on_start(const std::shared_ptr<vsomeip::message> /*&_message*/); + void on_stop(const std::shared_ptr<vsomeip::message> /*&_message*/); +}; +void check_memory(std::vector<std::uint64_t> &test_memory_); + +#endif // MEMORY_TEST_SERVICE_HPP_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/CMakeLists.txt new file mode 100644 index 00000000000..6bf2047d3a7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/CMakeLists.txt @@ -0,0 +1,139 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(npdu_tests LANGUAGES CXX) + +if(NOT TESTS_BAT AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "QNX") + + # Configure necessary files into the build folder. + set(configuration_files + npdu_test_client_no_npdu.json + npdu_test_client_no_npdu_start.sh + npdu_test_client_npdu.json + npdu_test_client_npdu_start.sh + npdu_test_service_no_npdu.json + npdu_test_service_no_npdu_start.sh + npdu_test_service_npdu.json + npdu_test_service_npdu_start.sh + npdu_test_starter.sh + ) + configure_files("${configuration_files}") + + # Routing managers. + + # Add test executable. + add_executable(npdu_test_rmd_client_side + npdu_test_rmd.cpp + ) + set_target_properties(npdu_test_rmd_client_side + PROPERTIES COMPILE_FLAGS -DRMD_CLIENT_SIDE + ) + + # Add test executable. + add_executable(npdu_test_rmd_service_side + npdu_test_rmd.cpp + ) + set_target_properties(npdu_test_rmd_service_side + PROPERTIES COMPILE_FLAGS -DRMD_SERVICE_SIDE + ) + + # Add build dependencies and link libraries to executables. + set(routing_managers + npdu_test_rmd_client_side + npdu_test_rmd_service_side + ) + targets_add_default_dependencies("${routing_managers}") + targets_link_default_libraries("${routing_managers}") + + # Clients and Services. + + # Add test executable. + add_executable(npdu_test_service_1 + npdu_test_service.cpp + ) + set_target_properties(npdu_test_service_1 + PROPERTIES COMPILE_FLAGS -DSERVICE_NUMBER=0 + ) + + # Add test executable. + add_executable(npdu_test_service_2 + npdu_test_service.cpp + ) + set_target_properties(npdu_test_service_2 + PROPERTIES COMPILE_FLAGS -DSERVICE_NUMBER=1 + ) + + # Add test executable. + add_executable(npdu_test_service_3 + npdu_test_service.cpp + ) + set_target_properties(npdu_test_service_3 + PROPERTIES COMPILE_FLAGS -DSERVICE_NUMBER=2 + ) + + # Add test executable. + add_executable(npdu_test_service_4 + npdu_test_service.cpp + ) + set_target_properties(npdu_test_service_4 + PROPERTIES COMPILE_FLAGS -DSERVICE_NUMBER=3 + ) + + # Add test executable. + add_executable(npdu_test_client_1 + npdu_test_client.cpp + ) + + # Add test executable. + add_executable(npdu_test_client_2 + npdu_test_client.cpp + ) + + # Add test executable. + add_executable(npdu_test_client_3 + npdu_test_client.cpp + ) + + # Add test executable. + add_executable(npdu_test_client_4 + npdu_test_client.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + npdu_test_service_1 + npdu_test_service_2 + npdu_test_service_3 + npdu_test_service_4 + npdu_test_client_1 + npdu_test_client_2 + npdu_test_client_3 + npdu_test_client_4 + ) + targets_add_default_dependencies("${executables}") + targets_link_default_libraries("${executables}") + + # Link executables to vsomeip-cfg. + foreach(target ${executables}) + target_link_libraries(${target} ${VSOMEIP_NAME}-cfg) + endforeach() + + # Add custom test command. + add_custom_test( + NAME npdu_test_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/npdu_test_starter.sh UDP sync + TIMEOUT 840 + ) + + # Add custom test command. + add_custom_test( + NAME npdu_test_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/npdu_test_starter.sh TCP sync + TIMEOUT 840 + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu.json.in new file mode 100644 index 00000000000..07cfe08c600 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu.json.in @@ -0,0 +1,39 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true" + }, + "applications": + [ + { + "name":"npdu_test_routing_manager_daemon_client_side", + "id":"0x6666" + }, + { + "name":"npdu_test_client_one", + "id":"0x1111" + }, + { + "name":"npdu_test_client_two", + "id":"0x2222" + }, + { + "name":"npdu_test_client_three", + "id":"0x3333" + }, + { + "name":"npdu_test_client_four", + "id":"0x4444" + } + ], + "routing":"npdu_test_routing_manager_daemon_client_side", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu_start.sh.in new file mode 100755 index 00000000000..bc844217cee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_no_npdu_start.sh.in @@ -0,0 +1,82 @@ +#!/bin/bash +# Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the routing manager daemon and the +# clients with one command. This is necessary as ctest - which is used to run +# the tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the routing +# manager daemon and the clients and checks if all of them exit successfully. + +FAIL=0 + +if [ $# -lt 2 ]; then + echo "Error: Please pass a protocol and communication mode to this script." + echo "Valid protocols are [UDP,TCP]." + echo "Valid communication modes are [sync, async]." + echo "For example $> $0 UDP sync" + exit 1; +fi + +FAIL=0 +PROTOCOL=$1 +COMMUNICATION_MODE=$2 + +start_clients(){ + export VSOMEIP_CONFIGURATION=npdu_test_client_no_npdu.json + + # Start the routing manager daemon + export VSOMEIP_APPLICATION_NAME=npdu_test_routing_manager_daemon_client_side + ./npdu_test_rmd_client_side & + + # sleep 1 second to let the RMD startup. + sleep 1 + # Start client 1 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_one + ./npdu_test_client_1 $* & + + # Start client 2 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_two + ./npdu_test_client_2 $* & + + # Start client 3 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_three + ./npdu_test_client_3 $* & + + # Start client 4 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_four + ./npdu_test_client_4 $* & +} + +wait_for_bg_processes(){ + # Wait until client and service are finished + for job in $(jobs -p) + do + # Fail gets incremented if one of the jobs exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) + done + + # Check if everything exited successfully + if [ $FAIL -eq 0 ] + then + echo "All clients exited successfully" + else + echo "Something went wrong" + exit 1 + fi +} + +if [ $# -eq 0 ] +then + echo "Error: Please pass a mode to this script: UDP or TCP." + echo "For example $> $0 UDP" +fi + +echo "Contacting services via $PROTOCOL" +start_clients --$PROTOCOL --max-payload-size $PROTOCOL --$COMMUNICATION_MODE +wait_for_bg_processes + +exit 0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu.json.in new file mode 100644 index 00000000000..dc35023c55e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu.json.in @@ -0,0 +1,167 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true" + }, + "applications": + [ + { + "name":"npdu_test_routing_manager_daemon_client_side", + "id":"0x6666" + }, + { + "name":"npdu_test_client_one", + "id":"0x1111" + }, + { + "name":"npdu_test_client_two", + "id":"0x2222" + }, + { + "name":"npdu_test_client_three", + "id":"0x3333" + }, + { + "name":"npdu_test_client_four", + "id":"0x4444" + } + ], + "services": + [ + { + "service":"0x1000", + "instance":"0x0001", + "unicast":"@TEST_IP_MASTER@", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": + { + "requests" : { + "0x1001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x1002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x1003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x1004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x2000", + "instance":"0x0002", + "unicast":"@TEST_IP_MASTER@", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times" : { + "requests" : { + "0x2001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x2002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x2003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x2004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x3000", + "instance":"0x0003", + "unicast":"@TEST_IP_MASTER@", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times" : { + "requests" : { + "0x3001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x3002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x3003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x3004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x4000", + "instance":"0x0004", + "unicast":"@TEST_IP_MASTER@", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": { + "requests" : { + "0x4001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x4002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x4003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x4004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + } + ], + "routing":"npdu_test_routing_manager_daemon_client_side", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu_start.sh.in new file mode 100755 index 00000000000..70b6c5312f2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_client_npdu_start.sh.in @@ -0,0 +1,75 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the routing manager daemon and the +# clients with one command. This is necessary as ctest - which is used to run +# the tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the routing +# manager daemon and the clients and checks if all of them exit successfully. + +if [ $# -lt 2 ]; then + echo "Error: Please pass a protocol and communication mode to this script." + echo "Valid protocols are [UDP,TCP]." + echo "Valid communication modes are [sync, async]." + echo "For example $> $0 UDP sync" + exit 1; +fi + +FAIL=0 +PROTOCOL=$1 +COMMUNICATION_MODE=$2 + +start_clients(){ + export VSOMEIP_CONFIGURATION=npdu_test_client_npdu.json + + # Start the routing manager daemon + export VSOMEIP_APPLICATION_NAME=npdu_test_routing_manager_daemon_client_side + ./npdu_test_rmd_client_side & + + # sleep 1 second to let the RMD startup. + sleep 1 + # Start client 1 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_one + ./npdu_test_client_1 $* & + + # Start client 2 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_two + ./npdu_test_client_2 $* & + + # Start client 3 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_three + ./npdu_test_client_3 $* & + + # Start client 4 + export VSOMEIP_APPLICATION_NAME=npdu_test_client_four + ./npdu_test_client_4 $* & +} + +wait_for_bg_processes(){ + # Wait until client and service are finished + for job in $(jobs -p) + do + # Fail gets incremented if one of the jobs exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) + done + + # Check if everything exited successfully + if [ $FAIL -eq 0 ] + then + echo "All clients exited successfully" + else + echo "Something went wrong" + exit 1 + fi +} + + +echo "Contacting services via $PROTOCOL" +start_clients --$PROTOCOL --max-payload-size $PROTOCOL --$COMMUNICATION_MODE +wait_for_bg_processes + +exit 0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu.json.in new file mode 100644 index 00000000000..b4c8eaa66f1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu.json.in @@ -0,0 +1,87 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true" + }, + "applications": + [ + { + "name":"npdu_test_routing_manager_daemon_service_side", + "id":"0x6667" + }, + { + "name":"npdu_test_service_one", + "id":"0x1000" + }, + { + "name":"npdu_test_service_two", + "id":"0x2000" + }, + { + "name":"npdu_test_service_three", + "id":"0x3000" + }, + { + "name":"npdu_test_service_four", + "id":"0x4000" + } + ], + "services": + [ + { + "service":"0x6667", + "instance":"0x6666", + "unreliable":"60666" + }, + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2000", + "instance":"0x0002", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3000", + "instance":"0x0003", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x4000", + "instance":"0x0004", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + } + } + ], + "routing":"npdu_test_routing_manager_daemon_service_side", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu_start.sh.in new file mode 100755 index 00000000000..cf05aaae87a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_no_npdu_start.sh.in @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the routing manager daemon and the +# services with one command. This is necessary as ctest - which is used to run +# the tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the routing +# manager daemon and the services and checks if all of them exit successfully. + +FAIL=0 + +start_services(){ + export VSOMEIP_CONFIGURATION=npdu_test_service_no_npdu.json + + # Start the routing manager daemon + export VSOMEIP_APPLICATION_NAME=npdu_test_routing_manager_daemon_service_side + ./npdu_test_rmd_service_side & + + # sleep 1 second to let the RMD startup. + sleep 1 + + # Start service 1 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_one + ./npdu_test_service_1 $* & + + # Start service 2 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_two + ./npdu_test_service_2 $* & + + # Start service 3 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_three + ./npdu_test_service_3 $* & + + # Start service 4 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_four + ./npdu_test_service_4 $* & +} + +wait_for_bg_processes(){ + # Wait until client and service are finished + for job in $(jobs -p) + do + # Fail gets incremented if one of the jobs exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) + done + + # Check if everything exited successfully + if [ $FAIL -eq 0 ] + then + echo "All services exited successfully" + else + echo "Something went wrong" + exit 1 + fi +} + +start_services +wait_for_bg_processes + +exit 0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu.json.in new file mode 100644 index 00000000000..0de75cfe6f9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu.json.in @@ -0,0 +1,168 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true" + }, + "applications": + [ + { + "name":"npdu_test_routing_manager_daemon_service_side", + "id":"0x6667" + }, + { + "name":"npdu_test_service_one", + "id":"0x1000" + }, + { + "name":"npdu_test_service_two", + "id":"0x2000" + }, + { + "name":"npdu_test_service_three", + "id":"0x3000" + }, + { + "name":"npdu_test_service_four", + "id":"0x4000" + } + ], + "services": + [ + { + "service":"0x6667", + "instance":"0x6666", + "unreliable":"60666" + }, + { + "service":"0x1000", + "instance":"0x0001", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": + { + "responses" : { + "0x1001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x1002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x1003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x1004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x2000", + "instance":"0x0002", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times" : { + "responses" : { + "0x2001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x2002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x2003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x2004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x3000", + "instance":"0x0003", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times" : { + "responses" : { + "0x3001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x3002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x3003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x3004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + }, + { + "service":"0x4000", + "instance":"0x0004", + "unreliable":"30509", + "reliable": + { + "port":"30510", + "enable-magic-cookies":"false" + }, + "debounce-times": { + "responses" : { + "0x4001" : { + "debounce-time" : "10", + "maximum-retention-time" : "100" + }, + "0x4002" : { + "debounce-time" : "20", + "maximum-retention-time" : "200" + }, + "0x4003" : { + "debounce-time" : "30", + "maximum-retention-time" : "300" + }, + "0x4004" : { + "debounce-time" : "40", + "maximum-retention-time" : "400" + } + } + } + } + ], + "routing":"npdu_test_routing_manager_daemon_service_side", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu_start.sh.in new file mode 100755 index 00000000000..0ca238b7ad3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_service_npdu_start.sh.in @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the routing manager daemon and the +# services with one command. This is necessary as ctest - which is used to run +# the tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the routing +# manager daemon and the services and checks if all of them exit successfully. + +FAIL=0 + +start_services(){ + export VSOMEIP_CONFIGURATION=npdu_test_service_npdu.json + + # Start the routing manager daemon + export VSOMEIP_APPLICATION_NAME=npdu_test_routing_manager_daemon_service_side + ./npdu_test_rmd_service_side & + + # sleep 1 second to let the RMD startup. + sleep 1 + + # Start service 1 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_one + ./npdu_test_service_1 $* & + + # Start service 2 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_two + ./npdu_test_service_2 $* & + + # Start service 3 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_three + ./npdu_test_service_3 $* & + + # Start service 4 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_four + ./npdu_test_service_4 $* & +} + +wait_for_bg_processes(){ + # Wait until client and service are finished + for job in $(jobs -p) + do + # Fail gets incremented if one of the jobs exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) + done + + # Check if everything exited successfully + if [ $FAIL -eq 0 ] + then + echo "All services exited successfully" + else + echo "Something went wrong" + exit 1 + fi +} + +start_services +wait_for_bg_processes + +exit 0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_starter.sh.in new file mode 100755 index 00000000000..b6aa490b508 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/conf/npdu_test_starter.sh.in @@ -0,0 +1,96 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the routing manager daemon and the +# services with one command. This is necessary as ctest - which is used to run +# the tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the routing +# manager daemon and the services and checks if all of them exit successfully. + +FAIL=0 + +if [ $# -lt 2 ]; then + echo "Error: Please pass a protocol and communication mode to this script." + echo "Valid protocols are [UDP,TCP]." + echo "Valid communication modes are [sync, async]." + echo "For example $> $0 UDP sync" + exit 1; +fi + +start_services(){ + export VSOMEIP_CONFIGURATION=npdu_test_service_npdu.json + + # Start the routing manager daemon + export VSOMEIP_APPLICATION_NAME=npdu_test_routing_manager_daemon_service_side + ./npdu_test_rmd_service_side & + + # sleep 1 second to let the RMD startup. + sleep 1 + + # Start service 1 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_one + ./npdu_test_service_1 $* & + + # Start service 2 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_two + ./npdu_test_service_2 $* & + + # Start service 3 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_three + ./npdu_test_service_3 $* & + + # Start service 4 + export VSOMEIP_APPLICATION_NAME=npdu_test_service_four + ./npdu_test_service_4 $* & +} + +wait_for_bg_processes(){ + # Wait until client and service are finished + for job in $(jobs -p) + do + # Fail gets incremented if one of the jobs exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) + done + + # Check if everything exited successfully + if [ $FAIL -eq 0 ] + then + echo "All services exited successfully" + else + echo "Something went wrong" + exit 1 + fi +} + + +start_services + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting magic cookies test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/npdu_tests; ./npdu_test_client_npdu_start.sh $*\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./npdu_test_client_npdu_start.sh $*" & +else +sleep 1 +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** npdu_test_client_npdu_start.sh $* +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** npdu_test_client_npdu.json and +** npdu_test_service_npdu.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +wait_for_bg_processes + +exit 0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.cpp new file mode 100644 index 00000000000..cba54f281cb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.cpp @@ -0,0 +1,602 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "../npdu_tests/npdu_test_client.hpp" + +#include <vsomeip/internal/logger.hpp> +#include "../../implementation/configuration/include/configuration.hpp" +#include "../../implementation/configuration/include/configuration_impl.hpp" +#include "../../implementation/configuration/include/configuration_plugin.hpp" +#include "../../implementation/plugin/include/plugin_manager_impl.hpp" + +enum class payloadsize + : std::uint8_t + { + UDS, TCP, UDP +}; + +// this variables are changed via cmdline parameters +static bool use_tcp = false; +static bool call_service_sync = true; +static bool wait_for_replies = true; +static std::uint32_t sliding_window_size = vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND; +static payloadsize max_payload_size = payloadsize::UDS; +static bool shutdown_service_at_end = true; + +npdu_test_client::npdu_test_client( + bool _use_tcp, + bool _call_service_sync, + std::uint32_t _sliding_window_size, + bool _wait_for_replies, + std::array<std::array<std::chrono::milliseconds, 4>, 4> _applicative_debounce) : + app_(vsomeip::runtime::get()->create_application()), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + call_service_sync_(_call_service_sync), + wait_for_replies_(_wait_for_replies), + sliding_window_size_(_sliding_window_size), + blocked_({false}), + is_available_({false}), // will set first element to false, rest to 0 + number_of_messages_to_send_(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND), + number_of_sent_messages_{0,0,0,0}, + number_of_acknowledged_messages_{{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, + current_payload_size_({0}), + all_msg_acknowledged_({false, false, false, false}), + acknowledgements_{0,0,0,0}, + applicative_debounce_(_applicative_debounce), + finished_waiter_(&npdu_test_client::wait_for_all_senders, this) +{ + senders_[0] = std::thread(&npdu_test_client::run<0>, this); + senders_[1] = std::thread(&npdu_test_client::run<1>, this); + senders_[2] = std::thread(&npdu_test_client::run<2>, this); + senders_[3] = std::thread(&npdu_test_client::run<3>, this); +} + +npdu_test_client::~npdu_test_client() { + finished_waiter_.join(); +} + +void npdu_test_client::init() +{ + app_->init(); + + app_->register_state_handler( + std::bind(&npdu_test_client::on_state, this, + std::placeholders::_1)); + + register_availability_handler<0>(); + register_availability_handler<1>(); + register_availability_handler<2>(); + register_availability_handler<3>(); + + register_message_handler_for_all_service_methods<0>(); + register_message_handler_for_all_service_methods<1>(); + register_message_handler_for_all_service_methods<2>(); + register_message_handler_for_all_service_methods<3>(); + + request_->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request_->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + if(!wait_for_replies_) + request_->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); +} + +template<int service_idx> +void npdu_test_client::register_availability_handler() { + app_->register_availability_handler(npdu_test::service_ids[service_idx], + npdu_test::instance_ids[service_idx], + std::bind( + &npdu_test_client::on_availability<service_idx>, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); +} + +template<int service_idx> +void npdu_test_client::register_message_handler_for_all_service_methods() { + register_message_handler<service_idx, 0>(); + register_message_handler<service_idx, 1>(); + register_message_handler<service_idx, 2>(); + register_message_handler<service_idx, 3>(); +} + +template<int service_idx, int method_idx> +void npdu_test_client::register_message_handler() { + app_->register_message_handler(npdu_test::service_ids[service_idx], + npdu_test::instance_ids[service_idx], + npdu_test::method_ids[service_idx][method_idx], + std::bind( + &npdu_test_client::on_message<service_idx, method_idx>, + this, std::placeholders::_1)); +} + +void npdu_test_client::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void npdu_test_client::stop() +{ + VSOMEIP_INFO << "Stopping..."; + + app_->unregister_state_handler(); + + for (unsigned int i = 0; i< npdu_test::service_ids.size(); i++) { + app_->unregister_availability_handler(npdu_test::service_ids[i], + npdu_test::instance_ids[i]); + + for(unsigned int j = 0; j < npdu_test::method_ids[i].size(); j++) { + app_->unregister_message_handler(npdu_test::service_ids[i], + npdu_test::instance_ids[i], + npdu_test::method_ids[i][j]); + } + } + + if(shutdown_service_at_end) { + // notify the routing manager daemon that were finished + request_->set_service(npdu_test::RMD_SERVICE_ID_CLIENT_SIDE); + request_->set_instance(npdu_test::RMD_INSTANCE_ID); + request_->set_method(npdu_test::RMD_SHUTDOWN_METHOD_ID); + request_->set_payload(vsomeip::runtime::get()->create_payload()); + request_->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + app_->send(request_); + // sleep otherwise the app will shutdown before the message reaches the rmd + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + app_->stop(); +} + +void npdu_test_client::join_sender_thread() { + for (auto& t : senders_) { + t.join(); + } +} + +void npdu_test_client::on_state(vsomeip::state_type_e _state) +{ + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + for (unsigned int i = 0; i< npdu_test::service_ids.size(); i++) { + app_->request_service(npdu_test::service_ids[i], + npdu_test::instance_ids[i]); + } + } +} + +template<int service_idx> +void npdu_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) +{ + VSOMEIP_INFO<< "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << std::setw(4) << std::setfill('0') << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + if(npdu_test::service_ids[service_idx] == _service + && npdu_test::instance_ids[service_idx] == _instance) { + if(is_available_[service_idx] && !_is_available) + { + is_available_[service_idx] = false; + } + else if(_is_available && !is_available_[service_idx]) + { + is_available_[service_idx] = true; + send<service_idx>(); + } + } +} + +template<int service_idx, int method_idx> +void npdu_test_client::on_message(const std::shared_ptr<vsomeip::message>& _response) { + (void)_response; + //TODO make sure the replies were sent within demanded debounce times + VSOMEIP_DEBUG << "Received reply from:" << std::setw(4) << std::setfill('0') + << std::hex << npdu_test::service_ids[service_idx] << ":" + << std::setw(4) << std::setfill('0') << std::hex + << npdu_test::instance_ids[service_idx] << ":" << std::setw(4) + << std::setfill('0') << std::hex + << npdu_test::method_ids[service_idx][method_idx]; + + if(call_service_sync_) + { + // We notify the sender thread every time a message was acknowledged + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutexes_[service_idx][method_idx]); + all_msg_acknowledged_[service_idx][method_idx] = true; + all_msg_acknowledged_cvs_[service_idx][method_idx].notify_one(); + } + else + { + + std::lock_guard<std::mutex> its_lock(number_of_acknowledged_messages_mutexes_[service_idx][method_idx]); + number_of_acknowledged_messages_[service_idx][method_idx]++; + + // We notify the sender thread only if all sent messages have been acknowledged + if(number_of_acknowledged_messages_[service_idx][method_idx] == number_of_messages_to_send_) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutexes_[service_idx][method_idx]); + // reset + number_of_acknowledged_messages_[service_idx][method_idx] = 0; + all_msg_acknowledged_[service_idx][method_idx] = true; + all_msg_acknowledged_cvs_[service_idx][method_idx].notify_one(); + } else if(number_of_acknowledged_messages_[service_idx][method_idx] % sliding_window_size == 0) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutexes_[service_idx][method_idx]); + all_msg_acknowledged_[service_idx][method_idx] = true; + all_msg_acknowledged_cvs_[service_idx][method_idx].notify_one(); + } + } +} + +template<int service_idx> +void npdu_test_client::send() +{ + std::lock_guard<std::mutex> its_lock(mutexes_[service_idx]); + blocked_[service_idx] = true; + conditions_[service_idx].notify_one(); +} + +template<int service_idx> +void npdu_test_client::run() +{ + std::unique_lock<std::mutex> its_lock(mutexes_[service_idx]); + while (!blocked_[service_idx]) + { + conditions_[service_idx].wait(its_lock); + } + current_payload_size_[service_idx] = 1; + + std::uint32_t max_allowed_payload = get_max_allowed_payload(); + + for (int var = 0; var < 4; ++var) { + payloads_[service_idx][var] = vsomeip::runtime::get()->create_payload(); + payload_data_[service_idx][var] = std::vector<vsomeip::byte_t>(); + } + + bool lastrun = false; + while (current_payload_size_[service_idx] <= max_allowed_payload) + { + // prepare the payloads w/ current payloadsize + for (int var = 0; var < 4; ++var) { + // assign 0x11 to first, 0x22 to second... + payload_data_[service_idx][var].assign( + current_payload_size_[service_idx], static_cast<vsomeip::byte_t>(0x11 * (var + 1))); + payloads_[service_idx][var]->set_data(payload_data_[service_idx][var]); + } + + // send the payloads to the service's methods + if(wait_for_replies_) { + call_service_sync_ ? send_messages_sync<service_idx>() : send_messages_async<service_idx>(); + } else { + send_messages_and_dont_wait_for_reply<service_idx>(); + } + + // Increase array size for next iteration + current_payload_size_[service_idx] *= 2; + + //special case to test the biggest payload possible as last test + // 16 Bytes are reserved for the SOME/IP header + if(current_payload_size_[service_idx] > max_allowed_payload - 16 && !lastrun) + { + current_payload_size_[service_idx] = max_allowed_payload - 16; + lastrun = true; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + blocked_[service_idx] = false; + + { + std::lock_guard<std::mutex> its_lock(finished_mutex_); + finished_[service_idx] = true; + } +} + + +std::uint32_t npdu_test_client::get_max_allowed_payload() +{ + std::uint32_t payload; + switch (max_payload_size) + { + case payloadsize::UDS: + payload = VSOMEIP_MAX_LOCAL_MESSAGE_SIZE; + break; + case payloadsize::TCP: + payload = 4095; + break; + case payloadsize::UDP: + payload = VSOMEIP_MAX_UDP_MESSAGE_SIZE; + break; + default: + payload = VSOMEIP_MAX_LOCAL_MESSAGE_SIZE; + break; + } + return payload; +} + +template<int service_idx> +void npdu_test_client::send_messages_sync() +{ + std::thread t0 = start_send_thread_sync<service_idx, 0>(); + std::thread t1 = start_send_thread_sync<service_idx, 1>(); + std::thread t2 = start_send_thread_sync<service_idx, 2>(); + std::thread t3 = start_send_thread_sync<service_idx, 3>(); + t0.join(); + t1.join(); + t2.join(); + t3.join(); +} + +template<int service_idx, int method_idx> +std::thread npdu_test_client::start_send_thread_sync() { + return std::thread([&]() { + all_msg_acknowledged_unique_locks_[service_idx][method_idx] = + std::unique_lock<std::mutex> + (all_msg_acknowledged_mutexes_[service_idx][method_idx]); + + std::shared_ptr<vsomeip::message> request = vsomeip::runtime::get()->create_request(use_tcp); + request->set_service(npdu_test::service_ids[service_idx]); + request->set_instance(npdu_test::instance_ids[service_idx]); + request->set_method(npdu_test::method_ids[service_idx][method_idx]); + request->set_payload(payloads_[service_idx][method_idx]); + for (std::uint32_t i = 0; i < number_of_messages_to_send_; i++) + { + all_msg_acknowledged_[service_idx][method_idx] = false; + app_->send(request); + + std::chrono::high_resolution_clock::time_point sent = + std::chrono::high_resolution_clock::now(); + + while(!all_msg_acknowledged_[service_idx][method_idx]) { + all_msg_acknowledged_cvs_[service_idx][method_idx].wait( + all_msg_acknowledged_unique_locks_[service_idx][method_idx]); + } + + std::chrono::nanoseconds waited_for_response = + std::chrono::high_resolution_clock::now() - sent; + if(waited_for_response < applicative_debounce_[service_idx][method_idx]) { + // make sure we don't send faster than debounce time + max retention time + std::this_thread::sleep_for( + applicative_debounce_[service_idx][method_idx] + - waited_for_response); + } + } + all_msg_acknowledged_unique_locks_[service_idx][method_idx].unlock(); + }); +} + +template<int service_idx> +void npdu_test_client::send_messages_async() +{ + std::thread t0 = start_send_thread_async<service_idx, 0>(); + std::thread t1 = start_send_thread_async<service_idx, 1>(); + std::thread t2 = start_send_thread_async<service_idx, 2>(); + std::thread t3 = start_send_thread_async<service_idx, 3>(); + t0.join(); + t1.join(); + t2.join(); + t3.join(); +} + +template<int service_idx, int method_idx> +std::thread npdu_test_client::start_send_thread_async() { + return std::thread([&]() { + all_msg_acknowledged_unique_locks_[service_idx][method_idx] = + std::unique_lock<std::mutex> + (all_msg_acknowledged_mutexes_[service_idx][method_idx]); + std::shared_ptr<vsomeip::message> request = vsomeip::runtime::get()->create_request(use_tcp); + request->set_service(npdu_test::service_ids[service_idx]); + request->set_instance(npdu_test::instance_ids[service_idx]); + request->set_method(npdu_test::method_ids[service_idx][method_idx]); + request->set_payload(payloads_[service_idx][method_idx]); + for (std::uint32_t i = 0; i < number_of_messages_to_send_; i++) + { + app_->send(request); + + if((i+1) == number_of_messages_to_send_ || (i+1) % sliding_window_size == 0) { + // wait until all send messages have been acknowledged + // as long we wait lk is released; after wait returns lk is reacquired + while(!all_msg_acknowledged_[service_idx][method_idx]) { + all_msg_acknowledged_cvs_[service_idx][method_idx].wait( + all_msg_acknowledged_unique_locks_[service_idx][method_idx]); + } + // Reset condition variable + all_msg_acknowledged_[service_idx][method_idx] = false; + } + // make sure we don't send faster than debounce time + max retention time + std::this_thread::sleep_for(applicative_debounce_[service_idx][method_idx]); + } + all_msg_acknowledged_unique_locks_[service_idx][method_idx].unlock(); + }); +} + +template<int service_idx> +void npdu_test_client::send_messages_and_dont_wait_for_reply() +{ + std::thread t0 = start_send_thread<service_idx, 0>(); + std::thread t1 = start_send_thread<service_idx, 1>(); + std::thread t2 = start_send_thread<service_idx, 2>(); + std::thread t3 = start_send_thread<service_idx, 3>(); + t0.join(); + t1.join(); + t2.join(); + t3.join(); +} + +template<int service_idx, int method_idx> +std::thread npdu_test_client::start_send_thread() { + return std::thread([&]() { + std::shared_ptr<vsomeip::message> request = vsomeip::runtime::get()->create_request(use_tcp); + request->set_service(npdu_test::service_ids[service_idx]); + request->set_instance(npdu_test::instance_ids[service_idx]); + request->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + request->set_method(npdu_test::method_ids[service_idx][method_idx]); + request->set_payload(payloads_[service_idx][method_idx]); + for (std::uint32_t i = 0; i < number_of_messages_to_send_; i++) + { + app_->send(request); + // make sure we don't send faster than debounce time + max retention time + std::this_thread::sleep_for(applicative_debounce_[service_idx][method_idx]); + } + }); +} + +void npdu_test_client::wait_for_all_senders() { + bool all_finished(false); + while (!all_finished) { + { + std::lock_guard<std::mutex> its_lock(finished_mutex_); + if (std::all_of(finished_.begin(), finished_.end(), [](bool i) { return i; })) { + all_finished = true; + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + join_sender_thread(); + + if (!wait_for_replies_ || !call_service_sync_) { + // sleep longer here as sending is asynchronously and it's necessary + // to wait until all messages have left the application + VSOMEIP_INFO << "Sleeping for 180sec since the client is running " + "in --dont-wait-for-replies or --async mode. " + "Otherwise it might be possible that not all messages leave the " + "application."; + for(int i = 0; i < 180; i++) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "."; + std::cout.flush(); + } + } else { + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + stop(); +} + +TEST(someip_npdu_test, send_different_payloads) +{ + // get the configuration + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_config_plugin = std::dynamic_pointer_cast<vsomeip::configuration_plugin>(its_plugin); + if (its_config_plugin) { + its_configuration = its_config_plugin->get_configuration("",""); + } + } + if (!its_configuration) { + ADD_FAILURE() << "No configuration object. " + "Either memory overflow or loading error detected!"; + return; + } + + // used to store the debounce times + std::array<std::array<std::chrono::milliseconds, 4>, 4> applicative_debounce; + + // query the debouncetimes from the configuration. We want to know the + // debounce times which the _clients_ of this service have to comply with + // when they send requests to this service. + // This is necessary as we must ensure a applicative debouncing greater than + // debounce time + maximum retention time. Therefore the send threads sleep + // for this amount of time after sending a message. + for(int service_id = 0; service_id < 4; service_id++) { + for(int method_id = 0; method_id < 4; method_id++) { + std::chrono::nanoseconds debounce(0), retention(0); + its_configuration->get_configured_timing_requests( + npdu_test::service_ids[service_id], + its_configuration->get_unicast_address(npdu_test::service_ids[service_id], + npdu_test::instance_ids[service_id]), + its_configuration->get_unreliable_port( + npdu_test::service_ids[service_id], + npdu_test::instance_ids[service_id]), + npdu_test::method_ids[service_id][method_id], + &debounce, &retention); + if (debounce == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO) && + retention == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO)) { + // no timings specified don't don't sleep after sending... + applicative_debounce[service_id][method_id] = + std::chrono::milliseconds(0); + } else { + // we add 1 milliseconds to sleep a little bit longer + applicative_debounce[service_id][method_id] = std::chrono::duration_cast< + std::chrono::milliseconds>(debounce + retention) + + std::chrono::milliseconds(1); + + } + + } + } + + npdu_test_client test_client_(use_tcp, call_service_sync, + sliding_window_size, wait_for_replies, + applicative_debounce); + test_client_.init(); + test_client_.start(); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + std::string tcp_enable("--TCP"); + std::string udp_enable("--UDP"); + std::string sync_enable("--sync"); + std::string async_enable("--async"); + std::string no_reply_enable("--dont-wait-for-replies"); + std::string sliding_window_size_param("--sliding-window-size"); + std::string max_payload_size_param("--max-payload-size"); + std::string shutdown_service_disable_param("--dont-shutdown-service"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if (tcp_enable == argv[i]) { + use_tcp = true; + } else if (udp_enable == argv[i]) { + use_tcp = false; + } else if (sync_enable == argv[i]) { + call_service_sync = true; + } else if (async_enable == argv[i]) { + call_service_sync = false; + } else if (no_reply_enable == argv[i]) { + wait_for_replies = false; + } else if (sliding_window_size_param == argv[i] && i + 1 < argc) { + i++; + std::stringstream converter(argv[i]); + converter >> sliding_window_size; + } else if (max_payload_size_param == argv[i] && i + 1 < argc) { + i++; + if (std::string("UDS") == argv[i]) { + max_payload_size = payloadsize::UDS; + } else if (std::string("TCP") == argv[i]) { + max_payload_size = payloadsize::TCP; + } else if (std::string("UDP") == argv[i]) { + max_payload_size = payloadsize::UDP; + } + } else if (shutdown_service_disable_param == argv[i]) { + shutdown_service_at_end = false; + } else if (help == argv[i]) { + VSOMEIP_INFO << "Parameters:\n" + << "--TCP: Send messages via TCP\n" + << "--UDP: Send messages via UDP (default)\n" + << "--sync: Wait for acknowledge before sending next message (default)\n" + << "--async: Send multiple messages w/o waiting for" + " acknowledge of service\n" + << "--dont-wait-for-replies: Just send out the messages w/o waiting for " + "a reply by the service (use REQUEST_NO_RETURN message type)\n" + << "--sliding-window-size: Number of messages to send before waiting " + "for acknowledge of service. Default: " << sliding_window_size << "\n" + << "--max-payload-size: limit the maximum payloadsize of send requests. One of {" + "UDS (=" << VSOMEIP_MAX_LOCAL_MESSAGE_SIZE << "byte), " + "UDP (=" << VSOMEIP_MAX_UDP_MESSAGE_SIZE << "byte), " + "TCP (=" << VSOMEIP_MAX_TCP_MESSAGE_SIZE << "byte)}, default: UDS\n" + << "--dont-shutdown-service: Don't shutdown the service upon " + "finishing of the payload test\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.hpp new file mode 100644 index 00000000000..2f469d40c04 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_client.hpp @@ -0,0 +1,104 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PAYLOADTESTCLIENT_HPP_ +#define NPDUTESTCLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> +#include <map> + +#include "../npdu_tests/npdu_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class npdu_test_client +{ +public: + npdu_test_client(bool _use_tcp, bool _call_service_sync, + std::uint32_t _sliding_window_size, + bool _wait_for_replies, + std::array<std::array<std::chrono::milliseconds, 4>, 4> _applicative_debounce); + ~npdu_test_client(); + void init(); + void start(); + void stop(); + void join_sender_thread(); + void on_state(vsomeip::state_type_e _state); + template<int service_idx> void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, + bool _is_available); + template<int service_idx, int method_idx> void on_message( + const std::shared_ptr<vsomeip::message> &_response); + template<int service_idx> void send(); + template<int service_idx> void run(); + +private: + template<int service_idx> void send_messages_sync(); + template<int service_idx, int method_idx> std::thread start_send_thread_sync(); + template<int service_idx> void send_messages_async(); + template<int service_idx, int method_idx> std::thread start_send_thread_async(); + template<int service_idx> void send_messages_and_dont_wait_for_reply(); + std::uint32_t get_max_allowed_payload(); + template<int service_idx> void register_availability_handler(); + template<int service_idx> void register_message_handler_for_all_service_methods(); + template<int service_idx, int method_idx> void register_message_handler(); + template<int service_idx, int method_idx> + std::thread start_send_thread(); + void wait_for_all_senders(); + +private: + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + bool call_service_sync_; + bool wait_for_replies_; + std::uint32_t sliding_window_size_; + + std::array<std::mutex, npdu_test::service_ids.size()> mutexes_; + std::array<std::condition_variable, npdu_test::service_ids.size()> conditions_; + std::array<bool, npdu_test::service_ids.size()> blocked_; + std::array<bool, npdu_test::service_ids.size()> is_available_; + const std::uint32_t number_of_messages_to_send_; + std::uint32_t number_of_sent_messages_[npdu_test::service_ids.size()]; + std::array<std::array<std::uint32_t, npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> number_of_acknowledged_messages_; + std::array<std::array<std::mutex, npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> number_of_acknowledged_messages_mutexes_; + + std::array<std::uint32_t, npdu_test::service_ids.size()> current_payload_size_; + + std::array<std::array<bool, npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> all_msg_acknowledged_; + std::array<std::array<std::mutex, npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> all_msg_acknowledged_mutexes_; + std::array<std::array<std::unique_lock<std::mutex>, npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> all_msg_acknowledged_unique_locks_; + std::array< + std::array<std::condition_variable, + npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> all_msg_acknowledged_cvs_; + std::array<std::uint32_t, 4> acknowledgements_; + std::array<std::array<std::chrono::milliseconds, 4>, 4> applicative_debounce_; + std::array< + std::array<std::shared_ptr<vsomeip::payload>, + npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> payloads_; + std::array< + std::array<std::vector<vsomeip::byte_t>, + npdu_test::method_ids[0].size()>, + npdu_test::service_ids.size()> payload_data_; + std::array<std::thread, npdu_test::service_ids.size()> senders_; + std::mutex finished_mutex_; + std::array<bool, npdu_test::service_ids.size()> finished_; + std::thread finished_waiter_; +}; + +#endif /* NPDUTESTCLIENT_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_globals.hpp new file mode 100644 index 00000000000..8cee3ee88ef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_globals.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NPDU_TESTS_NPDU_TEST_GLOBALS_HPP_ +#define NPDU_TESTS_NPDU_TEST_GLOBALS_HPP_ + +namespace npdu_test { + +// Routing manager daemon +constexpr vsomeip::client_t RMD_CLIENT_ID_CLIENT_SIDE = 0x6666; +constexpr vsomeip::service_t RMD_SERVICE_ID_CLIENT_SIDE = 0x6666; + +constexpr vsomeip::client_t RMD_CLIENT_ID_SERVICE_SIDE = 0x6667; +constexpr vsomeip::service_t RMD_SERVICE_ID_SERVICE_SIDE = 0x6667; + +constexpr vsomeip::instance_t RMD_INSTANCE_ID = 0x6666; +constexpr vsomeip::method_t RMD_SHUTDOWN_METHOD_ID = 0x6666; + + + +constexpr vsomeip::method_t NPDU_SERVICE_SHUTDOWNMETHOD_ID = 0x7777; + +constexpr std::array<vsomeip::service_t, 4> service_ids = + { 0x1000, 0x2000, 0x3000, 0x4000 }; +constexpr std::array<vsomeip::instance_t, 4> instance_ids = + { service_ids[0] >> 12, + service_ids[1] >> 12, + service_ids[2] >> 12, + service_ids[3] >> 12 }; +constexpr std::array<std::array<vsomeip::method_t, 4>, 4> method_ids = {{ + { service_ids[0]+1, service_ids[0]+2 ,service_ids[0]+3 ,service_ids[0]+4 }, + { service_ids[1]+1, service_ids[1]+2 ,service_ids[1]+3 ,service_ids[1]+4 }, + { service_ids[2]+1, service_ids[2]+2 ,service_ids[2]+3 ,service_ids[2]+4 }, + { service_ids[3]+1, service_ids[3]+2 ,service_ids[3]+3 ,service_ids[3]+4 } +}}; + +constexpr std::array<vsomeip::client_t, 4> client_ids_clients = + { 0x1111, 0x2222, 0x3333, 0x4444 }; + +constexpr std::array<vsomeip::client_t, 4> client_ids_services = service_ids; + +} +#endif /* NPDU_TESTS_NPDU_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.cpp new file mode 100644 index 00000000000..8e5451bd4d1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.cpp @@ -0,0 +1,160 @@ +// Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> + +#include "../npdu_tests/npdu_test_rmd.hpp" + +#include <vsomeip/internal/logger.hpp> +#include "npdu_test_globals.hpp" + +#include "../npdu_tests/npdu_test_globals.hpp" + +npdu_test_rmd::npdu_test_rmd() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + offer_thread_(std::bind(&npdu_test_rmd::run, this)) +{ + // TODO Auto-generated constructor stub +} + +void npdu_test_rmd::init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + app_->init(); + +#ifdef RMD_CLIENT_SIDE + app_->register_message_handler(npdu_test::RMD_SERVICE_ID_CLIENT_SIDE, +#elif defined (RMD_SERVICE_SIDE) + app_->register_message_handler(npdu_test::RMD_SERVICE_ID_SERVICE_SIDE, +#endif + npdu_test::RMD_INSTANCE_ID, npdu_test::RMD_SHUTDOWN_METHOD_ID, + std::bind(&npdu_test_rmd::on_message_shutdown, + this, std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&npdu_test_rmd::on_state, this, + std::placeholders::_1)); +} + +void npdu_test_rmd::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void npdu_test_rmd::stop() { + VSOMEIP_INFO << "Stopping..."; + + app_->unregister_message_handler(npdu_test::RMD_SERVICE_ID_CLIENT_SIDE, + npdu_test::RMD_INSTANCE_ID, npdu_test::RMD_SHUTDOWN_METHOD_ID); + app_->unregister_state_handler(); + offer_thread_.join(); + app_->stop(); +} + +void npdu_test_rmd::on_state( + vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void npdu_test_rmd::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) { + (void)_request; + std::shared_ptr<vsomeip::message> request = vsomeip::runtime::get()->create_request(false); +#ifdef RMD_CLIENT_SIDE + static uint32_t counter = 0; + counter++; + VSOMEIP_INFO << counter << " of " << npdu_test::client_ids_clients.size() + << " clients are finished."; + + if (counter == npdu_test::client_ids_clients.size()) { + VSOMEIP_INFO << "All clients are finished, notify routing manager daemon on service side."; + // notify the RMD_SERVICE_SIDE that he can shutdown as well + std::this_thread::sleep_for(std::chrono::seconds(1)); + request->set_service(npdu_test::RMD_SERVICE_ID_SERVICE_SIDE); + request->set_instance(npdu_test::RMD_INSTANCE_ID); + request->set_method(npdu_test::RMD_SHUTDOWN_METHOD_ID); + request->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + app_->send(request); + std::this_thread::sleep_for(std::chrono::seconds(5)); + stop(); + } +#elif defined RMD_SERVICE_SIDE + VSOMEIP_INFO << "All clients are finished shutting down services"; + // shutdown all services + for(unsigned int i = 0; i < npdu_test::service_ids.size(); i++) { + request->set_service(npdu_test::service_ids[i]); + request->set_instance(npdu_test::instance_ids[i]); + request->set_method(npdu_test::NPDU_SERVICE_SHUTDOWNMETHOD_ID); + request->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + app_->send(request); + } + app_->stop_offer_service(npdu_test::RMD_SERVICE_ID_SERVICE_SIDE, npdu_test::RMD_INSTANCE_ID); + + VSOMEIP_INFO << "Wait a few seconds until all services are shutdown."; + std::atomic<bool> finished(false); + for (int i = 0; !finished && i < 20; i++) { + app_->get_offered_services_async( + vsomeip::offer_type_e::OT_REMOTE, + [&](const std::vector<std::pair<vsomeip::service_t, + vsomeip::instance_t>> &_services){ + if (_services.empty()) { + finished = true; + } + }); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + stop(); +#endif +} + +void npdu_test_rmd::join_shutdown_thread() { + shutdown_thread_.join(); +} + +void npdu_test_rmd::run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); +#ifdef RMD_CLIENT_SIDE + app_->offer_service(npdu_test::RMD_SERVICE_ID_CLIENT_SIDE, npdu_test::RMD_INSTANCE_ID); +#elif defined (RMD_SERVICE_SIDE) + app_->offer_service(npdu_test::RMD_SERVICE_ID_SERVICE_SIDE, npdu_test::RMD_INSTANCE_ID); +#endif +} + +TEST(someip_npdu_test, offer_routing_manager_functionality) +{ + npdu_test_rmd daemon; + daemon.init(); + daemon.start(); +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.hpp new file mode 100644 index 00000000000..0b1e28dd94b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_rmd.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NPDU_TESTS_NPDUTESTROUTINGMANAGERDAEMON_HPP_ +#define NPDU_TESTS_NPDUTESTROUTINGMANAGERDAEMON_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +class npdu_test_rmd { + +public: + npdu_test_rmd(); + void init(); + void start(); + void stop(); + void on_state(vsomeip::state_type_e _state); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void join_shutdown_thread(); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::mutex mutex2_; + std::condition_variable condition_; + std::condition_variable condition2_; + bool blocked_; + bool blocked2_; + std::thread offer_thread_; + std::thread shutdown_thread_; + +}; + +#endif /* NPDU_TESTS_NPDUTESTROUTINGMANAGERDAEMON_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.cpp new file mode 100644 index 00000000000..3b13802a51c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.cpp @@ -0,0 +1,308 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "../npdu_tests/npdu_test_service.hpp" +#include "../npdu_tests/npdu_test_globals.hpp" + +#include <vsomeip/internal/logger.hpp> +#include "../../implementation/configuration/include/configuration.hpp" +#include "../../implementation/configuration/include/configuration_impl.hpp" +#include "../../implementation/configuration/include/configuration_plugin.hpp" +#include "../../implementation/plugin/include/plugin_manager_impl.hpp" + + + +// this variable is set during compile time to create 4 service binaries of +// which each of them offers a service. +// Based on this number the service id, instance id and method ids are +// selected from the arrays defined in npdu_test_globals.hpp +#ifndef SERVICE_NUMBER +#define SERVICE_NUMBER 0 +#endif + +npdu_test_service::npdu_test_service(vsomeip::service_t _service_id, + vsomeip::instance_t _instance_id, + std::array<vsomeip::method_t, 4> _method_ids, + std::array<std::chrono::nanoseconds, 4> _debounce_times, + std::array<std::chrono::nanoseconds, 4> _max_retention_times) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + method_ids_(_method_ids), + debounce_times_(_debounce_times), + max_retention_times_(_max_retention_times), + service_id_(_service_id), + instance_id_(_instance_id), + blocked_(false), + allowed_to_shutdown_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&npdu_test_service::run, this)), + shutdown_thread_(std::bind(&npdu_test_service::stop, this)) +{ + // init timepoints of last received message to one hour before now. + // needed that the first message which arrives isn't registered as undershot + // debounce time + for(auto &tp : timepoint_last_received_message_) { + tp = std::chrono::steady_clock::now() - std::chrono::hours(1); + } +} + +void npdu_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + app_->init(); + + register_message_handler<0>(); + register_message_handler<1>(); + register_message_handler<2>(); + register_message_handler<3>(); + + app_->register_message_handler(service_id_, instance_id_, + npdu_test::NPDU_SERVICE_SHUTDOWNMETHOD_ID, + std::bind(&npdu_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&npdu_test_service::on_state, this, + std::placeholders::_1)); +} + +template <int method_idx> +void npdu_test_service::register_message_handler() { + app_->register_message_handler(service_id_, instance_id_, method_ids_[method_idx], + std::bind(&npdu_test_service::on_message<method_idx>, this, + std::placeholders::_1)); +} + +void npdu_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void npdu_test_service::stop() +{ + std::unique_lock<std::mutex> its_lock(shutdown_mutex_); + while (!allowed_to_shutdown_) { + shutdown_condition_.wait(its_lock); + } + + VSOMEIP_INFO << "Stopping..."; + if (!undershot_debounce_times_.empty()) { + std::chrono::microseconds sum(0); + for (const auto t : undershot_debounce_times_) { + sum += t; + } + double average = static_cast<double>(sum.count())/static_cast<double>(undershot_debounce_times_.size()); + VSOMEIP_INFO << "[" + << std::setw(4) << std::setfill('0') << std::hex << service_id_ << "." + << std::setw(4) << std::setfill('0') << std::hex << instance_id_ << "]: " + << " Debounce time was undershot " << std::dec << undershot_debounce_times_.size() << "/" << number_of_received_messages_ + << "(" << std::setprecision(2) << (static_cast<double>(undershot_debounce_times_.size()) / static_cast<double>(number_of_received_messages_)) * 100.00 + << "%) on average: " << std::setprecision(4) << average << "µs"; + } + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[0]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[1]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[2]); + app_->unregister_message_handler(service_id_, instance_id_, method_ids_[3]); + app_->unregister_message_handler(service_id_, + instance_id_, npdu_test::NPDU_SERVICE_SHUTDOWNMETHOD_ID); + app_->unregister_state_handler(); + offer_thread_.join(); + stop_offer(); + app_->stop(); +} + +void npdu_test_service::offer() +{ + app_->offer_service(service_id_, instance_id_); +} + +void npdu_test_service::stop_offer() +{ + app_->stop_offer_service(service_id_, instance_id_); +} + +void npdu_test_service::join_shutdown_thread() { + shutdown_thread_.join(); +} + +void npdu_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +template<int method_idx> +void npdu_test_service::check_times() { + std::lock_guard<std::mutex> its_lock(timepoint_mutexes_[method_idx]); + // what time is it? + std::chrono::steady_clock::time_point now = + std::chrono::steady_clock::now(); + // how long is it since we received the last message? + std::chrono::nanoseconds time_since_last_message = + std::chrono::duration_cast<std::chrono::nanoseconds>( + now - timepoint_last_received_message_[method_idx]); + // store the current time + timepoint_last_received_message_[method_idx] = now; + + // check if the debounce time was undershot + if (time_since_last_message < debounce_times_[method_idx]) { + const auto time_undershot = std::chrono::duration_cast< + std::chrono::microseconds>(debounce_times_[method_idx] - time_since_last_message); + undershot_debounce_times_.push_back(time_undershot); + } + // check if maximum retention time was exceeded + // Disabled as it can't be guaranteed that exact every max retention time a + // message leaves the client endpoint. +#if 0 + if(time_since_last_message > max_retention_times_[method_idx]) { + VSOMEIP_ERROR << std::setw(4) << std::setfill('0') << std::hex + << service_id_ << ":" << std::setw(4) << std::setfill('0') + << std::hex << instance_id_ << ":" << std::setw(4) << std::setfill('0') + << std::hex << npdu_test::method_ids[SERVICE_NUMBER][method_idx] + << ": max_retention_time exceeded by: " << std::dec + << std::chrono::duration_cast<std::chrono::milliseconds>( + time_since_last_message - max_retention_times_[method_idx]).count() + << "ms"; + GTEST_FATAL_FAILURE_("Max retention time was exceeded"); + } +#endif +} + +template<int method_idx> +void npdu_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + number_of_received_messages_++; + check_times<method_idx>(); + VSOMEIP_DEBUG << __func__ << " 0x" << std::setw(4) << std::setfill('0') << std::hex + << method_ids_[method_idx] << " payload size: " + << std::dec << _request->get_payload()->get_length(); + if(_request->get_message_type() != vsomeip::message_type_e::MT_REQUEST_NO_RETURN) { + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + app_->send(its_response); + } +} + +void npdu_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) +{ + (void)_request; + VSOMEIP_DEBUG << "Number of received messages: " << number_of_received_messages_; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + allowed_to_shutdown_ = true; + shutdown_condition_.notify_one(); +} + +void npdu_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_npdu_test, offer_service_and_check_debounce_times) +{ + // get the configuration + std::shared_ptr<vsomeip::configuration> its_configuration; + auto its_plugin = vsomeip::plugin_manager::get()->get_plugin( + vsomeip::plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY); + if (its_plugin) { + auto its_config_plugin = std::dynamic_pointer_cast<vsomeip::configuration_plugin>(its_plugin); + if (its_config_plugin) { + its_configuration = its_config_plugin->get_configuration("",""); + } + } + if (!its_configuration) { + ADD_FAILURE() << "No configuration object. " + "Either memory overflow or loading error detected!"; + return; + } + + // used to store the debounce times + std::array<std::chrono::nanoseconds, 4> debounce_times; + std::array<std::chrono::nanoseconds, 4> max_retention_times; + + + // query the debouncetimes from the configuration. We want to know the + // debounce times which the _clients_ of this service have to comply with + // when they send requests to this service. This is necessary as we want to + // check on the service side if they adhere to them. + // client one will only query method one, client two will only query method + // two and so on. + for(int i = 0; i < 4; i++) { + std::chrono::nanoseconds debounce(0), retention(0); + its_configuration->get_configured_timing_requests( + npdu_test::service_ids[SERVICE_NUMBER], + its_configuration->get_unicast_address().to_string(), + its_configuration->get_unreliable_port( + npdu_test::service_ids[SERVICE_NUMBER], + npdu_test::instance_ids[SERVICE_NUMBER]), + npdu_test::method_ids[SERVICE_NUMBER][i], + &debounce_times[i], + &max_retention_times[i]); + if (debounce == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO) && + retention == std::chrono::nanoseconds(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO)) { + // no timings specified - checks in check_times() should never + // report an error in this case. + // set debounce time to 0 this can't be undershot + debounce_times[i] = std::chrono::nanoseconds(0); + // set max retention time its max, this won't be exceeded + max_retention_times[i] = std::chrono::nanoseconds::max(); + } + } + + npdu_test_service test_service( + npdu_test::service_ids[SERVICE_NUMBER], + npdu_test::instance_ids[SERVICE_NUMBER], + npdu_test::method_ids[SERVICE_NUMBER], + debounce_times, max_retention_times); + test_service.init(); + test_service.start(); + test_service.join_shutdown_thread(); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + int i = 1; + while (i < argc) + { + if(std::string("--help") == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.hpp new file mode 100644 index 00000000000..bef06806e31 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/npdu_tests/npdu_test_service.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NPDUTESTSERVICE_HPP_ +#define NPDUTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> +#include <chrono> +#include <deque> + +class npdu_test_service +{ +public: + npdu_test_service(vsomeip::service_t _service_id, + vsomeip::instance_t _instance_id, + std::array<vsomeip::method_t, 4> _method_ids, + std::array<std::chrono::nanoseconds, 4> _debounce_times, + std::array<std::chrono::nanoseconds, 4> _max_retention_times); + void init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_shutdown_thread(); + void on_state(vsomeip::state_type_e _state); + template<int method_idx> void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + template<int method_idx> void check_times(); + template <int method_idx> void register_message_handler(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + std::array<vsomeip::method_t, 4> method_ids_; + std::array<std::chrono::nanoseconds, 4> debounce_times_; + std::array<std::chrono::nanoseconds, 4> max_retention_times_; + std::array<std::chrono::steady_clock::time_point, 4> timepoint_last_received_message_; + std::array<std::mutex, 4> timepoint_mutexes_; + std::deque<std::chrono::microseconds> undershot_debounce_times_; + vsomeip::service_t service_id_; + vsomeip::instance_t instance_id_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::mutex shutdown_mutex_; + std::condition_variable shutdown_condition_; + bool allowed_to_shutdown_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; + std::thread shutdown_thread_; +}; + +#endif /* NPDUTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/CMakeLists.txt new file mode 100644 index 00000000000..716eb222501 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) +if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "QNX") +# Configure necessary files into the build folder. +set(configuration_files + offer_stop_offer_test_client.json + offer_stop_offer_test_client_starter.sh + offer_stop_offer_test_service.json + offer_stop_offer_test_service_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(offer_stop_offer_test_client + offer_stop_offer_test_client.cpp + applications/client.cpp +) + +# Add test executable. +add_executable(offer_stop_offer_test_service + offer_stop_offer_test_service.cpp + applications/service.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + offer_stop_offer_test_client + offer_stop_offer_test_service +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME offer_stop_offer_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offer_stop_offer_test_client_starter.sh + TIMEOUT 30 +) +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.cpp new file mode 100644 index 00000000000..d31f067c283 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <algorithm> +#include "client.hpp" +#include "service_ids.hpp" + +client_t::client_t() : + vsomeip_utilities::base_logger("CLI", "VSOMEIP SERVICE CONSUMER"), + vsomeip_app(vsomeip::runtime::get()->create_application("client-sample")) { + + availability_table[SERVICE_ID] = false; + availability_table[OTHER_SERVICE_ID] = false; +} + +client_t::~client_t() { + stop(); +} + +bool client_t::init() { + if (!vsomeip_app->init()) { + VSOMEIP_ERROR << "Couldn't initialize application"; + return false; + } + + vsomeip_app->register_message_handler( + SERVICE_ID, INSTANCE_ID, METHOD_ID, + std::bind(&client_t::on_message, this, std::placeholders::_1)); + vsomeip_app->register_message_handler( + OTHER_SERVICE_ID, OTHER_INSTANCE_ID, OTHER_METHOD_ID, + std::bind(&client_t::on_message, this, std::placeholders::_1)); + vsomeip_app->request_service(SERVICE_ID, INSTANCE_ID); + + vsomeip_app->register_availability_handler( + SERVICE_ID, INSTANCE_ID, + std::bind(&client_t::on_availability, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); + vsomeip_app->register_availability_handler( + OTHER_SERVICE_ID, OTHER_INSTANCE_ID, + std::bind(&client_t::on_availability, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); + vsomeip_app->request_service(OTHER_SERVICE_ID, OTHER_INSTANCE_ID); + + return true; +} + +void client_t::start() { + worker = std::thread([&] { vsomeip_app->start(); }); +} + +void client_t::stop() { + vsomeip_app->stop(); + if (worker.joinable()) { + worker.join(); + } +} + +std::future<bool> client_t::request(bool is_tcp, vsomeip::service_t service, + vsomeip::instance_t instance, vsomeip::method_t method) { + auto promise_response = std::promise<bool>(); + auto future_response = std::future<bool>(promise_response.get_future()); + + std::lock_guard<std::mutex> lk(availability_mutex); + if (availability_table[service]) { + auto request = vsomeip::runtime::get()->create_request(is_tcp); + + request->set_service(service); + request->set_instance(instance); + request->set_method(method); + + // store the pending request, so that we can set the promise later in on_message + pending_requests.push_back({service, instance, method, std::move(promise_response)}); + vsomeip_app->send(request); + + } else { + // set the value to false to notify the future that the request was not sent + promise_response.set_value(false); + } + + return future_response; +} + +bool client_t::is_available() { + std::lock_guard<std::mutex> lk(availability_mutex); + + for (const auto& availability_entry : availability_table) { + if (!availability_entry.second) { + return false; + } + } + return true; +} + +void client_t::on_message(const std::shared_ptr<vsomeip::message>& message) { + std::lock_guard<std::mutex> lk(availability_mutex); + + if (message->get_payload()->get_data()) { + VSOMEIP_INFO << "client_t::" << __func__ << ": " + << static_cast<int>(message->get_payload()->get_data()[0]) << " from 0x" + << std::setw(4) << std::setfill('0') << std::hex << message->get_service(); + } else { + VSOMEIP_WARNING << "client_t::" << __func__ << ": Empty payload for service " + << " from 0x" << std::setw(4) << std::setfill('0') << std::hex + << message->get_service(); + } + + for (auto it = pending_requests.begin(); it != pending_requests.end(); ++it) { + if (it->service == message->get_service() && it->instance == message->get_instance() + && it->method == message->get_method()) { + // set promise true as request was received and remove the pending_response + it->promise_response.set_value(true); + pending_requests.erase(it); + break; + } + } +} + +void client_t::on_availability(vsomeip::service_t service, vsomeip::instance_t instance, + bool is_available) { + std::lock_guard<std::mutex> lk(availability_mutex); + + VSOMEIP_INFO << "client_t::" << __func__ << " Service [" << std::setw(4) << std::setfill('0') + << std::hex << service << "." << instance << "] is " + << (is_available ? "available." : "NOT available."); + + availability_table[service] = is_available; + + // Service became unavailable -> set unblock futures + if (!is_available) { + pending_requests.erase(std::remove_if(pending_requests.begin(), pending_requests.end(), + [&](client_request_t& request) { + bool should_remove = (request.service == service) + && (request.instance == instance); + if (should_remove) { + request.promise_response.set_value(true); + } + return should_remove; + }), + pending_requests.end()); + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.hpp new file mode 100644 index 00000000000..f11e814177b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/client.hpp @@ -0,0 +1,104 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_CLIENT_HPP +#define VSOMEIP_CLIENT_HPP + +#include <future> +#include <list> +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <string> +#include <thread> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> +#include <common/vsomeip_app_utilities.hpp> + +/// @brief Wrapper for a vsomeip application that requests 2 services with a GET method +class client_t : public vsomeip_utilities::base_logger { +public: + /// @brief Initializes vsomeip application and availability table + client_t(); + + /// @brief Stops vsomeip application + ~client_t(); + + /// @brief Initializes vsomeip application and registers message and availability handlers + /// Also requests services. + /// + /// @return true if vsomeip->init() was successful + bool init(); + void start(); + void stop(); + + /// @brief Sends a someip request to the specified service. Will associate a promise with the + /// request, to later notify a future of the reception of its response. + /// + /// @param is_tcp If true the request will be sent via TCP. UDP will be used otherwise. + /// @param service Service to send the request to. + /// @param instance Instance to send the request to. + /// @param method Method to send the request to. + /// + /// @return returns a future that will notify that responde to this requests was received + std::future<bool> request(bool is_tcp, vsomeip::service_t service, + vsomeip::instance_t instance, + vsomeip::method_t method); + + /// @brief Check if both services are available + /// + /// @return true if both services are available; false if one or both were not available. + bool is_available(); + +private: + /// @brief handler for receiving responses. Will set the promise value of the received service. + /// + /// @param message Request message received + void on_message(const std::shared_ptr<vsomeip::message>& message); + + /// @brief handler for services availability. + /// + /// @param service Service that had its availability state changed + /// @param instance Instance that had its availability state changed + /// @param is_available New availability state + void on_availability(vsomeip::service_t service, vsomeip::instance_t instance, + bool is_available); + + /// @brief vsomeip app interface + std::shared_ptr<vsomeip::application> vsomeip_app; + + /// @brief availability table containing the availability state of both services + std::map<vsomeip::service_t, bool> availability_table; + + /// @brief availability table mutex + std::mutex availability_mutex; + + /// @brief background thread that will serve as context for the vsomeip application + std::thread worker; + + /// @brief Struct to hold the information of requests awaiting reponses + struct client_request_t { + /// @brief Request service + vsomeip::service_t service; + + /// @brief Request instance + vsomeip::instance_t instance; + + /// @brief Request method + vsomeip::method_t method; + + /// @brief promise which value shall be set once the response is received + std::promise<bool> promise_response; + }; + + /// @brief List to hold the current client_request_t awaiting responses. + /// client_request_t are removed after the response is received and promise is set. + std::list<client_request_t> pending_requests; + +}; + +#endif // VSOMEIP_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.cpp new file mode 100644 index 00000000000..1c6bac005dd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.cpp @@ -0,0 +1,138 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> +#include <future> + +#include "service.hpp" +#include "service_ids.hpp" + +constexpr std::size_t PAYLOAD_SIZE = 1000UL; + +service_t::service_t() : + vsomeip_utilities::base_logger("SRV", "VSOMEIP SERVICE PROVIDER"), + vsomeip_app(vsomeip::runtime::get()->create_application("service-sample")), + payload(std::vector<uint8_t>(PAYLOAD_SIZE, 0)) { + + availability_table[SERVICE_ID] = false; + availability_table[OTHER_SERVICE_ID] = false; +} + +service_t::~service_t() { + stop(); +} + +bool service_t::init() { + if (!vsomeip_app->init()) { + VSOMEIP_ERROR << "Couldn't initialize application" << std::endl; + return false; + } + + vsomeip_app->register_message_handler( + SERVICE_ID, INSTANCE_ID, METHOD_ID, + std::bind(&service_t::on_message, this, std::placeholders::_1)); + vsomeip_app->register_message_handler( + OTHER_SERVICE_ID, OTHER_INSTANCE_ID, OTHER_METHOD_ID, + std::bind(&service_t::on_message, this, std::placeholders::_1)); + + vsomeip_app->register_availability_handler( + SERVICE_ID, INSTANCE_ID, + std::bind(&service_t::on_availability, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); + vsomeip_app->register_availability_handler( + OTHER_SERVICE_ID, OTHER_INSTANCE_ID, + std::bind(&service_t::on_availability, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); + + vsomeip_app->offer_event(SERVICE_ID, INSTANCE_ID, EVENT_ID, {EVENTGROUP_ID}, + vsomeip::event_type_e::ET_FIELD); + vsomeip_app->offer_event(OTHER_SERVICE_ID, OTHER_INSTANCE_ID, EVENT_ID, {EVENTGROUP_ID}, + vsomeip::event_type_e::ET_FIELD); + + vsomeip_app->request_service(SERVICE_ID, INSTANCE_ID); + vsomeip_app->request_service(OTHER_SERVICE_ID, OTHER_INSTANCE_ID); + + return true; +} + +void service_t::start() { + worker = std::thread([&] { vsomeip_app->start(); }); +} + +void service_t::stop() { + vsomeip_app->stop(); + if (worker.joinable()) { + worker.join(); + } +} + +std::future<bool> service_t::offer() { + // Lock the entire function to not allow the on_availability callback to interfier while the + // offer is being created + std::lock_guard<std::mutex> lk(availability_mutex); + + VSOMEIP_INFO << "service_t::" << __func__; + vsomeip_app->offer_service(SERVICE_ID, INSTANCE_ID, 0, 0); + vsomeip_app->offer_service(OTHER_SERVICE_ID, OTHER_INSTANCE_ID, 0, 0); + + promise_availability = std::promise<bool>(); + auto future_availability = std::future<bool>(promise_availability.get_future()); + + is_offering = true; + return future_availability; +} + +std::future<bool> service_t::stop_offer() { + // Lock the entire function to not allow the on_availability callback to interfier while the + // offer is being created + std::lock_guard<std::mutex> lk(availability_mutex); + + VSOMEIP_INFO << "service_t::" << __func__; + vsomeip_app->stop_offer_service(SERVICE_ID, INSTANCE_ID, 0, 0); + vsomeip_app->stop_offer_service(OTHER_SERVICE_ID, OTHER_INSTANCE_ID, 0, 0); + + promise_availability = std::promise<bool>(); + auto future_availability = std::future<bool>(promise_availability.get_future()); + + is_offering = false; + return future_availability; +} + +void service_t::on_message(const std::shared_ptr<vsomeip::message>& message) { + std::lock_guard<std::mutex> lk(availability_mutex); + + payload.at(0)++; + VSOMEIP_INFO << "service_t::" << __func__ << ": [" << std::hex << message->get_service() << "] " + << static_cast<int>(payload.at(0)); + + auto vsomeip_payload = vsomeip::runtime::get()->create_payload(payload); + auto its_response = vsomeip::runtime::get()->create_response(message); + its_response->set_payload(vsomeip_payload); + + vsomeip_app->send(its_response); +} + +void service_t::on_availability(vsomeip::service_t service, vsomeip::instance_t instance, + bool is_available) { + std::lock_guard<std::mutex> lk(availability_mutex); + + VSOMEIP_INFO << "service_t::" << __func__ << " Service [" << std::setw(4) << std::setfill('0') + << std::hex << service << "." << instance << "] is " + << (is_available ? "available." : "NOT available."); + + availability_table[service] = is_available; + + // check if all services are in the same state of is_offering + bool all_availabilities_confirmed = true; + for (const auto& availability_entry : availability_table) { + if (availability_entry.second != is_offering) { + all_availabilities_confirmed = false; + } + } + if (all_availabilities_confirmed) { + // If all services are -> set promise + promise_availability.set_value(is_offering); + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.hpp new file mode 100644 index 00000000000..2802959aa6c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service.hpp @@ -0,0 +1,89 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_SERVICE_HPP +#define VSOMEIP_SERVICE_HPP + +#include <future> +#include <list> +#include <memory> +#include <mutex> +#include <set> +#include <string> +#include <thread> +#include <vector> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> +#include <common/vsomeip_app_utilities.hpp> + +/// @brief Wrapper for a vsomeip application that offers 2 services with a GET method +class service_t : public vsomeip_utilities::base_logger { +public: + /// @brief Initializes vsomeip application and availability table + service_t(); + + /// @brief Stops vsomeip application + ~service_t(); + + /// @brief Initializes vsomeip application and registers message and availability handlers + /// Also requests own services to force the routing manager to offer them. + /// + /// @return true if vsomeip->init() was successful + bool init(); + + /// @brief Starts vsomeip application on a background thread. Non blocking call. + void start(); + + /// @brief Stops vsomeip application + void stop(); + + /// @brief Offers both services + /// + /// @return returns a future that will notify that the availability to this service was changed + std::future<bool> offer(); + + /// @brief Stops offering both services + /// + /// @return returns a future that will notify that the availability to this service was changed + std::future<bool> stop_offer(); + +private: + /// @brief handler for receiving requests. Will send a response back with a big payload and a + /// changing first byte + /// + /// @param message Request message received + void on_message(const std::shared_ptr<vsomeip::message>& message); + + /// @brief handler for services availability. + /// + /// @param service Service that had its availability state changed + /// @param instance Instance that had its availability state changed + /// @param is_available New availability state + void on_availability(vsomeip::service_t service, vsomeip::instance_t instance, + bool is_available); + + /// @brief vsomeip app interface + std::shared_ptr<vsomeip::application> vsomeip_app; + + /// @brief payload sent in the responde of the requests + std::vector<uint8_t> payload; + + /// @brief availability table containing the availability state of both services + std::map<vsomeip::service_t, bool> availability_table; + /// @brief availability table mutex + std::mutex availability_mutex; + + /// @brief background thread that will serve as context for the vsomeip application + std::thread worker; + + /// @brief application offer state for both services. + bool is_offering; + + /// @brief promise which value shall be set once the availability is received + std::promise<bool> promise_availability; +}; + +#endif // VSOMEIP_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service_ids.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service_ids.hpp new file mode 100644 index 00000000000..0a44b76e7fe --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/applications/service_ids.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_SERVICE_IDS_HPP +#define VSOMEIP_SERVICE_IDS_HPP + +#include <vsomeip/vsomeip.hpp> + +/// @brief First service id +constexpr vsomeip::service_t SERVICE_ID = 0x1234; + +/// @brief First service instance id +constexpr vsomeip::instance_t INSTANCE_ID = 0x5678; + +/// @brief First service method id +constexpr vsomeip::method_t METHOD_ID = 0x0421; + +/// @brief Second service id +constexpr vsomeip::service_t OTHER_SERVICE_ID = 0x1235; + +/// @brief Second service instance id +constexpr vsomeip::instance_t OTHER_INSTANCE_ID = 0x5678; + +/// @brief Second service method id +constexpr vsomeip::method_t OTHER_METHOD_ID = 0x0421; + +/// @brief Both services event id +constexpr vsomeip::event_t EVENT_ID = 0x8778; + +/// @brief Both services eventgroup id +constexpr vsomeip::eventgroup_t EVENTGROUP_ID = 0x4465; + + +#endif // VSOMEIP_EXAMPLES_IDS_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client.json.in new file mode 100644 index 00000000000..da44753c048 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client.json.in @@ -0,0 +1,32 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "debug", + "console" : "true", + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1343" + } + ], + "clients" : + [ + { + "reliable_remote_ports" : { "first" : "30501", "last" : "30506" }, + "reliable_client_ports" : { "first" : "30491", "last" : "30493" } + } + ], + "routing" : "client-sample", + "service-discovery": + { + "enable": "true", + "multicast": "224.244.224.245", + "port": "30490", + "protocol": "udp", + "cyclic_offer_delay": "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client_starter.sh.in new file mode 100755 index 00000000000..ee6676de084 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_client_starter.sh.in @@ -0,0 +1,19 @@ +#!/bin/bash +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +# call other container +if [ ! -z "$USE_LXC_TEST" ]; then + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/offer_stop_offer_test; ./offer_stop_offer_test_service_starter.sh\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./offer_stop_offer_test_service_starter.sh" & +fi + +# start client +export VSOMEIP_CONFIGURATION=offer_stop_offer_test_client.json +export VSOMEIP_APPLICATION_NAME="client-sample" +./offer_stop_offer_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service.json.in new file mode 100644 index 00000000000..88386277bc5 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service.json.in @@ -0,0 +1,73 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "debug", + "console" : "true", + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "routingmanagerd", + "id" : "0x1200" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "reliable" : "30506", + "events" : + [ + { + "event" : "0x8778", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4465", + "events" : [ "0x8778" ] + + } + ] + }, + { + "service" : "0x1235", + "instance" : "0x5678", + "reliable" : "30506", + "unreliable" : "30506", + "events" : + [ + { + "event" : "0x8778", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4465", + "events" : [ "0x8778" ] + + } + ] + } + ], + "routing" : "routingmanagerd", + "service-discovery": + { + "enable": "true", + "multicast": "224.244.224.245", + "port": "30490", + "protocol": "udp", + "cyclic_offer_delay": "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service_starter.sh.in new file mode 100755 index 00000000000..451613e8330 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/conf/offer_stop_offer_test_service_starter.sh.in @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# start routing host +export VSOMEIP_CONFIGURATION=offer_stop_offer_test_service.json +export VSOMEIP_APPLICATION_NAME="routingmanagerd" +../../../examples/routingmanagerd/routingmanagerd & + +HOST_PID=$! + +# start service app +export VSOMEIP_CONFIGURATION=offer_stop_offer_test_service.json +export VSOMEIP_APPLICATION_NAME="service-sample" + +./offer_stop_offer_test_service + +kill -9 $HOST_PID diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_client.cpp new file mode 100644 index 00000000000..b5df59ff9f6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_client.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <future> +#include <vector> +#include <string> +#include <iostream> +#include <iomanip> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> +#include <common/vsomeip_app_utilities.hpp> +#include <common/test_timer.hpp> + +#include <gtest/gtest.h> + +#include "applications/client.hpp" +#include "applications/service_ids.hpp" +#include "offer_stop_offer_test_helper.hpp" + +TEST(test_offer_stop_offer, test_offer_stop_offer_client) { + // Precondition 1: Service consumer application initializes correctly + client_t service_consumer; + + ASSERT_TRUE(service_consumer.init()); + service_consumer.start(); + + // Test steps: + // > If service is available: + // 1: send 3 request messages (service_1 via tcp, service_2 via tcp, service_3 via udp) + // 2: validate that the requests were sent + // 3: validate that the response was received + // + // *Note_1: The value of the future itself is not relavant, only that is was set + // *Note_2: There can be the situation where the service goes unavailable while the + // requests are being sent. In that case the future is set either way, so we don't + // need to worry here in the test. + // + // > If service is not available + // 1: do nothing + // + // At the end validate that the service was available, atleast once + test_timer_t test_timer(CLIENT_UP_TIME); + bool service_was_available = false; + bool request_was_received = false; + while (!test_timer.has_elapsed()) { + if (service_consumer.is_available()) { + service_was_available = true; + + auto request_service1_tcp = + service_consumer.request(true, SERVICE_ID, INSTANCE_ID, METHOD_ID); + auto request_service2_tcp = + service_consumer.request(true, OTHER_SERVICE_ID, OTHER_INSTANCE_ID, METHOD_ID); + auto request_service2_udp = + service_consumer.request(false, OTHER_SERVICE_ID, OTHER_INSTANCE_ID, METHOD_ID); + + // check if futures are valid + ASSERT_TRUE(request_service1_tcp.valid()); + ASSERT_TRUE(request_service2_tcp.valid()); + ASSERT_TRUE(request_service2_udp.valid()); + + // wait for responses + request_service1_tcp.wait(); + request_service2_tcp.wait(); + request_service2_udp.wait(); + + request_was_received = true; + } + } + + // to not get mislead if the service was never up + EXPECT_TRUE(service_was_available); + // to not get mislead if the request was never received + EXPECT_TRUE(request_was_received); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_helper.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_helper.hpp new file mode 100644 index 00000000000..33474c42384 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_helper.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef TEST_OFFER_STOP_OFFER_HELPER_HPP +#define TEST_OFFER_STOP_OFFER_HELPER_HPP + +#include <chrono> + +/// @brief Time for which the service application is active +constexpr auto SERVICE_UP_TIME = std::chrono::seconds(9); + +/// @brief Time for which the service application is offering the services and responding to +/// requests +constexpr auto SERVICE_OFFER_TIME = std::chrono::milliseconds(500); + +/// @brief Time for which the service application stops offering the services +constexpr auto SERVICE_STOP_OFFER_TIME = std::chrono::milliseconds(2); + +/// @brief Time for which the client application is active +constexpr auto CLIENT_UP_TIME = std::chrono::seconds(10); + +#endif // TEST_OFFER_STOP_OFFER_HELPER_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_service.cpp new file mode 100644 index 00000000000..0b4ac043cd3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_stop_offer_test/offer_stop_offer_test_service.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <future> +#include <vector> +#include <string> +#include <iostream> +#include <iomanip> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> +#include <common/vsomeip_app_utilities.hpp> +#include <common/test_timer.hpp> + +#include <gtest/gtest.h> + +#include "applications/service.hpp" +#include "offer_stop_offer_test_helper.hpp" + +TEST(test_offer_stop_offer, test_offer_stop_offer_service) { + // Precondition 1: Service provider application initializes correctly + service_t service_provider; + + ASSERT_TRUE(service_provider.init()); + service_provider.start(); + + // Precondition 2: routingmanagerd is able to route + auto routing_availability_check = service_provider.offer(); + ASSERT_TRUE(routing_availability_check.valid()); + routing_availability_check.wait(); + ASSERT_TRUE(routing_availability_check.get()) << "routingmanagerd was not ready in time!"; + + test_timer_t test_timer(SERVICE_UP_TIME); + + // Test steps: + // 1: STOP_OFFERING the services for SERVICE_STOP_OFFER_TIME + // 2: validate that the services are not available + // 3: OFFER the services again + // 4: validate that the services are available + // Repeate above steps for SERVICE_UP_TIME + while (!test_timer.has_elapsed()) { + + auto stop_offer_confirmation = service_provider.stop_offer(); + // Wait confirmation that all services have became unavailable + ASSERT_TRUE(stop_offer_confirmation.valid()); + stop_offer_confirmation.wait(); + ASSERT_FALSE(stop_offer_confirmation.get()) << "stop_offer was not confirmed in time!"; + + std::this_thread::sleep_for(SERVICE_STOP_OFFER_TIME); + + auto offer_confirmation = service_provider.offer(); + // Wait confirmation that all services have became available + ASSERT_TRUE(offer_confirmation.valid()); + offer_confirmation.wait(); + ASSERT_TRUE(offer_confirmation.get()) << "offer was not confirmed in time!"; + + std::this_thread::sleep_for(SERVICE_OFFER_TIME); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/CMakeLists.txt new file mode 100644 index 00000000000..67ff1e7d9bf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/CMakeLists.txt @@ -0,0 +1,101 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(offer_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + offer_test_big_sd_msg_master.json + offer_test_big_sd_msg_master_starter.sh + offer_test_big_sd_msg_slave.json + offer_test_big_sd_msg_slave_starter.sh + offer_test_external_master.json + offer_test_external_master_starter.sh + offer_test_external_slave.json + offer_test_external_slave_starter.sh + offer_test_local.json + offer_test_local_starter.sh + offer_test_multiple_offerings.json + offer_test_multiple_offerings_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(offer_test_service + offer_test_service.cpp +) + +# Add test executable. +add_executable(offer_test_multiple_offerings + offer_test_multiple_offerings.cpp +) + +# Add test executable. +add_executable(offer_test_client + offer_test_client.cpp +) + +# Add test executable. +add_executable(offer_test_service_external + offer_test_service_external.cpp +) + +# Add test executable. +add_executable(offer_test_external_sd_msg_sender + offer_test_external_sd_msg_sender.cpp +) + +# Add test executable. +add_executable(offer_test_big_sd_msg_service + offer_test_big_sd_msg_service.cpp +) + +# Add test executable. +add_executable(offer_test_big_sd_msg_client + offer_test_big_sd_msg_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + offer_test_service + offer_test_multiple_offerings + offer_test_client + offer_test_service_external + offer_test_external_sd_msg_sender + offer_test_big_sd_msg_service + offer_test_big_sd_msg_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME offer_test_local + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offer_test_local_starter.sh + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME offer_test_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offer_test_external_master_starter.sh + TIMEOUT 360 +) + +# Add custom test command. +add_custom_test( + NAME offer_test_big_sd_msg + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offer_test_big_sd_msg_master_starter.sh + TIMEOUT 360 +) + +# Add custom test command. +add_custom_test( + NAME offer_test_multiple_offerings + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offer_test_multiple_offerings_starter.sh + TIMEOUT 1800 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master.json.in new file mode 100644 index 00000000000..6f1e65965a9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master.json.in @@ -0,0 +1,31 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "offer_test_big_sd_msg_client", + "id" : "0x6666" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "ttl" : "3", + "multicast":"224.0.11.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master_starter.sh.in new file mode 100755 index 00000000000..e934238b314 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_master_starter.sh.in @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +export VSOMEIP_CONFIGURATION=offer_test_big_sd_msg_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +./offer_test_big_sd_msg_client & +CLIENT_PID=$! + + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_big_sd_msg_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/offer_tests; ./offer_test_big_sd_msg_slave_starter.sh\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && sleep 10; ./offer_test_big_sd_msg_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** offer_test_big_sd_msg_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** offer_test_big_sd_msg_master.json and +** offer_test_big_sd_msg_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +for job in $CLIENT_PID +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# wait for slave to finish +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + echo "[Master] waiting for job $job" + wait $job || ((FAIL+=1)) +done + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave.json.in new file mode 100644 index 00000000000..34263fd77e2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave.json.in @@ -0,0 +1,334 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "offer_test_big_sd_msg_service", + "id" : "0x7777" + } + ], + "services": + [ + {"service":"0x1","instance":"0x1","unreliable":"30001","reliable":{"port":"30001","enable-magic-cookies":"false"}}, + {"service":"0x2","instance":"0x1","unreliable":"30002","reliable":{"port":"30002","enable-magic-cookies":"false"}}, + {"service":"0x3","instance":"0x1","unreliable":"30003","reliable":{"port":"30003","enable-magic-cookies":"false"}}, + {"service":"0x4","instance":"0x1","unreliable":"30004","reliable":{"port":"30004","enable-magic-cookies":"false"}}, + {"service":"0x5","instance":"0x1","unreliable":"30005","reliable":{"port":"30005","enable-magic-cookies":"false"}}, + {"service":"0x6","instance":"0x1","unreliable":"30006","reliable":{"port":"30006","enable-magic-cookies":"false"}}, + {"service":"0x7","instance":"0x1","unreliable":"30007","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x8","instance":"0x1","unreliable":"30008","reliable":{"port":"30008","enable-magic-cookies":"false"}}, + {"service":"0x9","instance":"0x1","unreliable":"60000","reliable":{"port":"30009","enable-magic-cookies":"false"}}, + {"service":"0xA","instance":"0x1","unreliable":"30010","reliable":{"port":"30010","enable-magic-cookies":"false"}}, + {"service":"0xB","instance":"0x1","unreliable":"30011","reliable":{"port":"30011","enable-magic-cookies":"false"}}, + {"service":"0xC","instance":"0x1","unreliable":"30012","reliable":{"port":"30012","enable-magic-cookies":"false"}}, + {"service":"0xD","instance":"0x1","unreliable":"30013","reliable":{"port":"30013","enable-magic-cookies":"false"}}, + {"service":"0xE","instance":"0x1","unreliable":"30014","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xF","instance":"0x1","unreliable":"30015","reliable":{"port":"30015","enable-magic-cookies":"false"}}, + {"service":"0x10","instance":"0x1","unreliable":"30016","reliable":{"port":"30016","enable-magic-cookies":"false"}}, + {"service":"0x11","instance":"0x1","unreliable":"30017","reliable":{"port":"30017","enable-magic-cookies":"false"}}, + {"service":"0x12","instance":"0x1","unreliable":"60000","reliable":{"port":"30018","enable-magic-cookies":"false"}}, + {"service":"0x13","instance":"0x1","unreliable":"30019","reliable":{"port":"30019","enable-magic-cookies":"false"}}, + {"service":"0x14","instance":"0x1","unreliable":"30020","reliable":{"port":"30020","enable-magic-cookies":"false"}}, + {"service":"0x15","instance":"0x1","unreliable":"30021","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x16","instance":"0x1","unreliable":"30022","reliable":{"port":"30022","enable-magic-cookies":"false"}}, + {"service":"0x17","instance":"0x1","unreliable":"30023","reliable":{"port":"30023","enable-magic-cookies":"false"}}, + {"service":"0x18","instance":"0x1","unreliable":"30024","reliable":{"port":"30024","enable-magic-cookies":"false"}}, + {"service":"0x19","instance":"0x1","unreliable":"30025","reliable":{"port":"30025","enable-magic-cookies":"false"}}, + {"service":"0x1A","instance":"0x1","unreliable":"30026","reliable":{"port":"30026","enable-magic-cookies":"false"}}, + {"service":"0x1B","instance":"0x1","unreliable":"60000","reliable":{"port":"30027","enable-magic-cookies":"false"}}, + {"service":"0x1C","instance":"0x1","unreliable":"30028","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x1D","instance":"0x1","unreliable":"30029","reliable":{"port":"30029","enable-magic-cookies":"false"}}, + {"service":"0x1E","instance":"0x1","unreliable":"30030","reliable":{"port":"30030","enable-magic-cookies":"false"}}, + {"service":"0x1F","instance":"0x1","unreliable":"30031","reliable":{"port":"30031","enable-magic-cookies":"false"}}, + {"service":"0x20","instance":"0x1","unreliable":"30032","reliable":{"port":"30032","enable-magic-cookies":"false"}}, + {"service":"0x21","instance":"0x1","unreliable":"30033","reliable":{"port":"30033","enable-magic-cookies":"false"}}, + {"service":"0x22","instance":"0x1","unreliable":"30034","reliable":{"port":"30034","enable-magic-cookies":"false"}}, + {"service":"0x23","instance":"0x1","unreliable":"30035","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x24","instance":"0x1","unreliable":"60000","reliable":{"port":"30036","enable-magic-cookies":"false"}}, + {"service":"0x25","instance":"0x1","unreliable":"30037","reliable":{"port":"30037","enable-magic-cookies":"false"}}, + {"service":"0x26","instance":"0x1","unreliable":"30038","reliable":{"port":"30038","enable-magic-cookies":"false"}}, + {"service":"0x27","instance":"0x1","unreliable":"30039","reliable":{"port":"30039","enable-magic-cookies":"false"}}, + {"service":"0x28","instance":"0x1","unreliable":"30040","reliable":{"port":"30040","enable-magic-cookies":"false"}}, + {"service":"0x29","instance":"0x1","unreliable":"30041","reliable":{"port":"30041","enable-magic-cookies":"false"}}, + {"service":"0x2A","instance":"0x1","unreliable":"30042","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x2B","instance":"0x1","unreliable":"30043","reliable":{"port":"30043","enable-magic-cookies":"false"}}, + {"service":"0x2C","instance":"0x1","unreliable":"30044","reliable":{"port":"30044","enable-magic-cookies":"false"}}, + {"service":"0x2D","instance":"0x1","unreliable":"60000","reliable":{"port":"30045","enable-magic-cookies":"false"}}, + {"service":"0x2E","instance":"0x1","unreliable":"30046","reliable":{"port":"30046","enable-magic-cookies":"false"}}, + {"service":"0x2F","instance":"0x1","unreliable":"30047","reliable":{"port":"30047","enable-magic-cookies":"false"}}, + {"service":"0x30","instance":"0x1","unreliable":"30048","reliable":{"port":"30048","enable-magic-cookies":"false"}}, + {"service":"0x31","instance":"0x1","unreliable":"30049","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x32","instance":"0x1","unreliable":"30050","reliable":{"port":"30050","enable-magic-cookies":"false"}}, + {"service":"0x33","instance":"0x1","unreliable":"30051","reliable":{"port":"30051","enable-magic-cookies":"false"}}, + {"service":"0x34","instance":"0x1","unreliable":"30052","reliable":{"port":"30052","enable-magic-cookies":"false"}}, + {"service":"0x35","instance":"0x1","unreliable":"30053","reliable":{"port":"30053","enable-magic-cookies":"false"}}, + {"service":"0x36","instance":"0x1","unreliable":"60000","reliable":{"port":"30054","enable-magic-cookies":"false"}}, + {"service":"0x37","instance":"0x1","unreliable":"30055","reliable":{"port":"30055","enable-magic-cookies":"false"}}, + {"service":"0x38","instance":"0x1","unreliable":"30056","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x39","instance":"0x1","unreliable":"30057","reliable":{"port":"30057","enable-magic-cookies":"false"}}, + {"service":"0x3A","instance":"0x1","unreliable":"30058","reliable":{"port":"30058","enable-magic-cookies":"false"}}, + {"service":"0x3B","instance":"0x1","unreliable":"30059","reliable":{"port":"30059","enable-magic-cookies":"false"}}, + {"service":"0x3C","instance":"0x1","unreliable":"30060","reliable":{"port":"30060","enable-magic-cookies":"false"}}, + {"service":"0x3D","instance":"0x1","unreliable":"30061","reliable":{"port":"30061","enable-magic-cookies":"false"}}, + {"service":"0x3E","instance":"0x1","unreliable":"30062","reliable":{"port":"30062","enable-magic-cookies":"false"}}, + {"service":"0x3F","instance":"0x1","unreliable":"60000","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x40","instance":"0x1","unreliable":"30064","reliable":{"port":"30064","enable-magic-cookies":"false"}}, + {"service":"0x41","instance":"0x1","unreliable":"30065","reliable":{"port":"30065","enable-magic-cookies":"false"}}, + {"service":"0x42","instance":"0x1","unreliable":"30066","reliable":{"port":"30066","enable-magic-cookies":"false"}}, + {"service":"0x43","instance":"0x1","unreliable":"30067","reliable":{"port":"30067","enable-magic-cookies":"false"}}, + {"service":"0x44","instance":"0x1","unreliable":"30068","reliable":{"port":"30068","enable-magic-cookies":"false"}}, + {"service":"0x45","instance":"0x1","unreliable":"30069","reliable":{"port":"30069","enable-magic-cookies":"false"}}, + {"service":"0x46","instance":"0x1","unreliable":"30070","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x47","instance":"0x1","unreliable":"30071","reliable":{"port":"30071","enable-magic-cookies":"false"}}, + {"service":"0x48","instance":"0x1","unreliable":"60000","reliable":{"port":"30072","enable-magic-cookies":"false"}}, + {"service":"0x49","instance":"0x1","unreliable":"30073","reliable":{"port":"30073","enable-magic-cookies":"false"}}, + {"service":"0x4A","instance":"0x1","unreliable":"30074","reliable":{"port":"30074","enable-magic-cookies":"false"}}, + {"service":"0x4B","instance":"0x1","unreliable":"30075","reliable":{"port":"30075","enable-magic-cookies":"false"}}, + {"service":"0x4C","instance":"0x1","unreliable":"30076","reliable":{"port":"30076","enable-magic-cookies":"false"}}, + {"service":"0x4D","instance":"0x1","unreliable":"30077","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x4E","instance":"0x1","unreliable":"30078","reliable":{"port":"30078","enable-magic-cookies":"false"}}, + {"service":"0x4F","instance":"0x1","unreliable":"30079","reliable":{"port":"30079","enable-magic-cookies":"false"}}, + {"service":"0x50","instance":"0x1","unreliable":"30080","reliable":{"port":"30080","enable-magic-cookies":"false"}}, + {"service":"0x51","instance":"0x1","unreliable":"60000","reliable":{"port":"30081","enable-magic-cookies":"false"}}, + {"service":"0x52","instance":"0x1","unreliable":"30082","reliable":{"port":"30082","enable-magic-cookies":"false"}}, + {"service":"0x53","instance":"0x1","unreliable":"30083","reliable":{"port":"30083","enable-magic-cookies":"false"}}, + {"service":"0x54","instance":"0x1","unreliable":"30084","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x55","instance":"0x1","unreliable":"30085","reliable":{"port":"30085","enable-magic-cookies":"false"}}, + {"service":"0x56","instance":"0x1","unreliable":"30086","reliable":{"port":"30086","enable-magic-cookies":"false"}}, + {"service":"0x57","instance":"0x1","unreliable":"30087","reliable":{"port":"30087","enable-magic-cookies":"false"}}, + {"service":"0x58","instance":"0x1","unreliable":"30088","reliable":{"port":"30088","enable-magic-cookies":"false"}}, + {"service":"0x59","instance":"0x1","unreliable":"30089","reliable":{"port":"30089","enable-magic-cookies":"false"}}, + {"service":"0x5A","instance":"0x1","unreliable":"60000","reliable":{"port":"30090","enable-magic-cookies":"false"}}, + {"service":"0x5B","instance":"0x1","unreliable":"30091","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x5C","instance":"0x1","unreliable":"30092","reliable":{"port":"30092","enable-magic-cookies":"false"}}, + {"service":"0x5D","instance":"0x1","unreliable":"30093","reliable":{"port":"30093","enable-magic-cookies":"false"}}, + {"service":"0x5E","instance":"0x1","unreliable":"30094","reliable":{"port":"30094","enable-magic-cookies":"false"}}, + {"service":"0x5F","instance":"0x1","unreliable":"30095","reliable":{"port":"30095","enable-magic-cookies":"false"}}, + {"service":"0x60","instance":"0x1","unreliable":"30096","reliable":{"port":"30096","enable-magic-cookies":"false"}}, + {"service":"0x61","instance":"0x1","unreliable":"30097","reliable":{"port":"30097","enable-magic-cookies":"false"}}, + {"service":"0x62","instance":"0x1","unreliable":"30098","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x63","instance":"0x1","unreliable":"60000","reliable":{"port":"30099","enable-magic-cookies":"false"}}, + {"service":"0x64","instance":"0x1","unreliable":"30100","reliable":{"port":"30100","enable-magic-cookies":"false"}}, + {"service":"0x65","instance":"0x1","unreliable":"30101","reliable":{"port":"30101","enable-magic-cookies":"false"}}, + {"service":"0x66","instance":"0x1","unreliable":"30102","reliable":{"port":"30102","enable-magic-cookies":"false"}}, + {"service":"0x67","instance":"0x1","unreliable":"30103","reliable":{"port":"30103","enable-magic-cookies":"false"}}, + {"service":"0x68","instance":"0x1","unreliable":"30104","reliable":{"port":"30104","enable-magic-cookies":"false"}}, + {"service":"0x69","instance":"0x1","unreliable":"30105","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x6A","instance":"0x1","unreliable":"30106","reliable":{"port":"30106","enable-magic-cookies":"false"}}, + {"service":"0x6B","instance":"0x1","unreliable":"30107","reliable":{"port":"30107","enable-magic-cookies":"false"}}, + {"service":"0x6C","instance":"0x1","unreliable":"60000","reliable":{"port":"30108","enable-magic-cookies":"false"}}, + {"service":"0x6D","instance":"0x1","unreliable":"30109","reliable":{"port":"30109","enable-magic-cookies":"false"}}, + {"service":"0x6E","instance":"0x1","unreliable":"30110","reliable":{"port":"30110","enable-magic-cookies":"false"}}, + {"service":"0x6F","instance":"0x1","unreliable":"30111","reliable":{"port":"30111","enable-magic-cookies":"false"}}, + {"service":"0x70","instance":"0x1","unreliable":"30112","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x71","instance":"0x1","unreliable":"30113","reliable":{"port":"30113","enable-magic-cookies":"false"}}, + {"service":"0x72","instance":"0x1","unreliable":"30114","reliable":{"port":"30114","enable-magic-cookies":"false"}}, + {"service":"0x73","instance":"0x1","unreliable":"30115","reliable":{"port":"30115","enable-magic-cookies":"false"}}, + {"service":"0x74","instance":"0x1","unreliable":"30116","reliable":{"port":"30116","enable-magic-cookies":"false"}}, + {"service":"0x75","instance":"0x1","unreliable":"60000","reliable":{"port":"30117","enable-magic-cookies":"false"}}, + {"service":"0x76","instance":"0x1","unreliable":"30118","reliable":{"port":"30118","enable-magic-cookies":"false"}}, + {"service":"0x77","instance":"0x1","unreliable":"30119","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x78","instance":"0x1","unreliable":"30120","reliable":{"port":"30120","enable-magic-cookies":"false"}}, + {"service":"0x79","instance":"0x1","unreliable":"30121","reliable":{"port":"30121","enable-magic-cookies":"false"}}, + {"service":"0x7A","instance":"0x1","unreliable":"30122","reliable":{"port":"30122","enable-magic-cookies":"false"}}, + {"service":"0x7B","instance":"0x1","unreliable":"30123","reliable":{"port":"30123","enable-magic-cookies":"false"}}, + {"service":"0x7C","instance":"0x1","unreliable":"30124","reliable":{"port":"30124","enable-magic-cookies":"false"}}, + {"service":"0x7D","instance":"0x1","unreliable":"30125","reliable":{"port":"30125","enable-magic-cookies":"false"}}, + {"service":"0x7E","instance":"0x1","unreliable":"60000","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x7F","instance":"0x1","unreliable":"30127","reliable":{"port":"30127","enable-magic-cookies":"false"}}, + {"service":"0x80","instance":"0x1","unreliable":"30128","reliable":{"port":"30128","enable-magic-cookies":"false"}}, + {"service":"0x81","instance":"0x1","unreliable":"30129","reliable":{"port":"30129","enable-magic-cookies":"false"}}, + {"service":"0x82","instance":"0x1","unreliable":"30130","reliable":{"port":"30130","enable-magic-cookies":"false"}}, + {"service":"0x83","instance":"0x1","unreliable":"30131","reliable":{"port":"30131","enable-magic-cookies":"false"}}, + {"service":"0x84","instance":"0x1","unreliable":"30132","reliable":{"port":"30132","enable-magic-cookies":"false"}}, + {"service":"0x85","instance":"0x1","unreliable":"30133","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x86","instance":"0x1","unreliable":"30134","reliable":{"port":"30134","enable-magic-cookies":"false"}}, + {"service":"0x87","instance":"0x1","unreliable":"60000","reliable":{"port":"30135","enable-magic-cookies":"false"}}, + {"service":"0x88","instance":"0x1","unreliable":"30136","reliable":{"port":"30136","enable-magic-cookies":"false"}}, + {"service":"0x89","instance":"0x1","unreliable":"30137","reliable":{"port":"30137","enable-magic-cookies":"false"}}, + {"service":"0x8A","instance":"0x1","unreliable":"30138","reliable":{"port":"30138","enable-magic-cookies":"false"}}, + {"service":"0x8B","instance":"0x1","unreliable":"30139","reliable":{"port":"30139","enable-magic-cookies":"false"}}, + {"service":"0x8C","instance":"0x1","unreliable":"30140","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x8D","instance":"0x1","unreliable":"30141","reliable":{"port":"30141","enable-magic-cookies":"false"}}, + {"service":"0x8E","instance":"0x1","unreliable":"30142","reliable":{"port":"30142","enable-magic-cookies":"false"}}, + {"service":"0x8F","instance":"0x1","unreliable":"30143","reliable":{"port":"30143","enable-magic-cookies":"false"}}, + {"service":"0x90","instance":"0x1","unreliable":"60000","reliable":{"port":"30144","enable-magic-cookies":"false"}}, + {"service":"0x91","instance":"0x1","unreliable":"30145","reliable":{"port":"30145","enable-magic-cookies":"false"}}, + {"service":"0x92","instance":"0x1","unreliable":"30146","reliable":{"port":"30146","enable-magic-cookies":"false"}}, + {"service":"0x93","instance":"0x1","unreliable":"30147","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x94","instance":"0x1","unreliable":"30148","reliable":{"port":"30148","enable-magic-cookies":"false"}}, + {"service":"0x95","instance":"0x1","unreliable":"30149","reliable":{"port":"30149","enable-magic-cookies":"false"}}, + {"service":"0x96","instance":"0x1","unreliable":"30150","reliable":{"port":"30150","enable-magic-cookies":"false"}}, + {"service":"0x97","instance":"0x1","unreliable":"30151","reliable":{"port":"30151","enable-magic-cookies":"false"}}, + {"service":"0x98","instance":"0x1","unreliable":"30152","reliable":{"port":"30152","enable-magic-cookies":"false"}}, + {"service":"0x99","instance":"0x1","unreliable":"60000","reliable":{"port":"30153","enable-magic-cookies":"false"}}, + {"service":"0x9A","instance":"0x1","unreliable":"30154","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x9B","instance":"0x1","unreliable":"30155","reliable":{"port":"30155","enable-magic-cookies":"false"}}, + {"service":"0x9C","instance":"0x1","unreliable":"30156","reliable":{"port":"30156","enable-magic-cookies":"false"}}, + {"service":"0x9D","instance":"0x1","unreliable":"30157","reliable":{"port":"30157","enable-magic-cookies":"false"}}, + {"service":"0x9E","instance":"0x1","unreliable":"30158","reliable":{"port":"30158","enable-magic-cookies":"false"}}, + {"service":"0x9F","instance":"0x1","unreliable":"30159","reliable":{"port":"30159","enable-magic-cookies":"false"}}, + {"service":"0xA0","instance":"0x1","unreliable":"30160","reliable":{"port":"30160","enable-magic-cookies":"false"}}, + {"service":"0xA1","instance":"0x1","unreliable":"30161","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xA2","instance":"0x1","unreliable":"60000","reliable":{"port":"30162","enable-magic-cookies":"false"}}, + {"service":"0xA3","instance":"0x1","unreliable":"30163","reliable":{"port":"30163","enable-magic-cookies":"false"}}, + {"service":"0xA4","instance":"0x1","unreliable":"30164","reliable":{"port":"30164","enable-magic-cookies":"false"}}, + {"service":"0xA5","instance":"0x1","unreliable":"30165","reliable":{"port":"30165","enable-magic-cookies":"false"}}, + {"service":"0xA6","instance":"0x1","unreliable":"30166","reliable":{"port":"30166","enable-magic-cookies":"false"}}, + {"service":"0xA7","instance":"0x1","unreliable":"30167","reliable":{"port":"30167","enable-magic-cookies":"false"}}, + {"service":"0xA8","instance":"0x1","unreliable":"30168","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xA9","instance":"0x1","unreliable":"30169","reliable":{"port":"30169","enable-magic-cookies":"false"}}, + {"service":"0xAA","instance":"0x1","unreliable":"30170","reliable":{"port":"30170","enable-magic-cookies":"false"}}, + {"service":"0xAB","instance":"0x1","unreliable":"60000","reliable":{"port":"30171","enable-magic-cookies":"false"}}, + {"service":"0xAC","instance":"0x1","unreliable":"30172","reliable":{"port":"30172","enable-magic-cookies":"false"}}, + {"service":"0xAD","instance":"0x1","unreliable":"30173","reliable":{"port":"30173","enable-magic-cookies":"false"}}, + {"service":"0xAE","instance":"0x1","unreliable":"30174","reliable":{"port":"30174","enable-magic-cookies":"false"}}, + {"service":"0xAF","instance":"0x1","unreliable":"30175","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xB0","instance":"0x1","unreliable":"30176","reliable":{"port":"30176","enable-magic-cookies":"false"}}, + {"service":"0xB1","instance":"0x1","unreliable":"30177","reliable":{"port":"30177","enable-magic-cookies":"false"}}, + {"service":"0xB2","instance":"0x1","unreliable":"30178","reliable":{"port":"30178","enable-magic-cookies":"false"}}, + {"service":"0xB3","instance":"0x1","unreliable":"30179","reliable":{"port":"30179","enable-magic-cookies":"false"}}, + {"service":"0xB4","instance":"0x1","unreliable":"60000","reliable":{"port":"30180","enable-magic-cookies":"false"}}, + {"service":"0xB5","instance":"0x1","unreliable":"30181","reliable":{"port":"30181","enable-magic-cookies":"false"}}, + {"service":"0xB6","instance":"0x1","unreliable":"30182","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xB7","instance":"0x1","unreliable":"30183","reliable":{"port":"30183","enable-magic-cookies":"false"}}, + {"service":"0xB8","instance":"0x1","unreliable":"30184","reliable":{"port":"30184","enable-magic-cookies":"false"}}, + {"service":"0xB9","instance":"0x1","unreliable":"30185","reliable":{"port":"30185","enable-magic-cookies":"false"}}, + {"service":"0xBA","instance":"0x1","unreliable":"30186","reliable":{"port":"30186","enable-magic-cookies":"false"}}, + {"service":"0xBB","instance":"0x1","unreliable":"30187","reliable":{"port":"30187","enable-magic-cookies":"false"}}, + {"service":"0xBC","instance":"0x1","unreliable":"30188","reliable":{"port":"30188","enable-magic-cookies":"false"}}, + {"service":"0xBD","instance":"0x1","unreliable":"60000","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xBE","instance":"0x1","unreliable":"30190","reliable":{"port":"30190","enable-magic-cookies":"false"}}, + {"service":"0xBF","instance":"0x1","unreliable":"30191","reliable":{"port":"30191","enable-magic-cookies":"false"}}, + {"service":"0xC0","instance":"0x1","unreliable":"30192","reliable":{"port":"30192","enable-magic-cookies":"false"}}, + {"service":"0xC1","instance":"0x1","unreliable":"30193","reliable":{"port":"30193","enable-magic-cookies":"false"}}, + {"service":"0xC2","instance":"0x1","unreliable":"30194","reliable":{"port":"30194","enable-magic-cookies":"false"}}, + {"service":"0xC3","instance":"0x1","unreliable":"30195","reliable":{"port":"30195","enable-magic-cookies":"false"}}, + {"service":"0xC4","instance":"0x1","unreliable":"30196","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xC5","instance":"0x1","unreliable":"30197","reliable":{"port":"30197","enable-magic-cookies":"false"}}, + {"service":"0xC6","instance":"0x1","unreliable":"60000","reliable":{"port":"30198","enable-magic-cookies":"false"}}, + {"service":"0xC7","instance":"0x1","unreliable":"30199","reliable":{"port":"30199","enable-magic-cookies":"false"}}, + {"service":"0xC8","instance":"0x1","unreliable":"30200","reliable":{"port":"30200","enable-magic-cookies":"false"}}, + {"service":"0xC9","instance":"0x1","unreliable":"30201","reliable":{"port":"30201","enable-magic-cookies":"false"}}, + {"service":"0xCA","instance":"0x1","unreliable":"30202","reliable":{"port":"30202","enable-magic-cookies":"false"}}, + {"service":"0xCB","instance":"0x1","unreliable":"30203","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xCC","instance":"0x1","unreliable":"30204","reliable":{"port":"30204","enable-magic-cookies":"false"}}, + {"service":"0xCD","instance":"0x1","unreliable":"30205","reliable":{"port":"30205","enable-magic-cookies":"false"}}, + {"service":"0xCE","instance":"0x1","unreliable":"30206","reliable":{"port":"30206","enable-magic-cookies":"false"}}, + {"service":"0xCF","instance":"0x1","unreliable":"60000","reliable":{"port":"30207","enable-magic-cookies":"false"}}, + {"service":"0xD0","instance":"0x1","unreliable":"30208","reliable":{"port":"30208","enable-magic-cookies":"false"}}, + {"service":"0xD1","instance":"0x1","unreliable":"30209","reliable":{"port":"30209","enable-magic-cookies":"false"}}, + {"service":"0xD2","instance":"0x1","unreliable":"30210","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xD3","instance":"0x1","unreliable":"30211","reliable":{"port":"30211","enable-magic-cookies":"false"}}, + {"service":"0xD4","instance":"0x1","unreliable":"30212","reliable":{"port":"30212","enable-magic-cookies":"false"}}, + {"service":"0xD5","instance":"0x1","unreliable":"30213","reliable":{"port":"30213","enable-magic-cookies":"false"}}, + {"service":"0xD6","instance":"0x1","unreliable":"30214","reliable":{"port":"30214","enable-magic-cookies":"false"}}, + {"service":"0xD7","instance":"0x1","unreliable":"30215","reliable":{"port":"30215","enable-magic-cookies":"false"}}, + {"service":"0xD8","instance":"0x1","unreliable":"60000","reliable":{"port":"30216","enable-magic-cookies":"false"}}, + {"service":"0xD9","instance":"0x1","unreliable":"30217","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xDA","instance":"0x1","unreliable":"30218","reliable":{"port":"30218","enable-magic-cookies":"false"}}, + {"service":"0xDB","instance":"0x1","unreliable":"30219","reliable":{"port":"30219","enable-magic-cookies":"false"}}, + {"service":"0xDC","instance":"0x1","unreliable":"30220","reliable":{"port":"30220","enable-magic-cookies":"false"}}, + {"service":"0xDD","instance":"0x1","unreliable":"30221","reliable":{"port":"30221","enable-magic-cookies":"false"}}, + {"service":"0xDE","instance":"0x1","unreliable":"30222","reliable":{"port":"30222","enable-magic-cookies":"false"}}, + {"service":"0xDF","instance":"0x1","unreliable":"30223","reliable":{"port":"30223","enable-magic-cookies":"false"}}, + {"service":"0xE0","instance":"0x1","unreliable":"30224","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xE1","instance":"0x1","unreliable":"60000","reliable":{"port":"30225","enable-magic-cookies":"false"}}, + {"service":"0xE2","instance":"0x1","unreliable":"30226","reliable":{"port":"30226","enable-magic-cookies":"false"}}, + {"service":"0xE3","instance":"0x1","unreliable":"30227","reliable":{"port":"30227","enable-magic-cookies":"false"}}, + {"service":"0xE4","instance":"0x1","unreliable":"30228","reliable":{"port":"30228","enable-magic-cookies":"false"}}, + {"service":"0xE5","instance":"0x1","unreliable":"30229","reliable":{"port":"30229","enable-magic-cookies":"false"}}, + {"service":"0xE6","instance":"0x1","unreliable":"30230","reliable":{"port":"30230","enable-magic-cookies":"false"}}, + {"service":"0xE7","instance":"0x1","unreliable":"30231","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xE8","instance":"0x1","unreliable":"30232","reliable":{"port":"30232","enable-magic-cookies":"false"}}, + {"service":"0xE9","instance":"0x1","unreliable":"30233","reliable":{"port":"30233","enable-magic-cookies":"false"}}, + {"service":"0xEA","instance":"0x1","unreliable":"60000","reliable":{"port":"30234","enable-magic-cookies":"false"}}, + {"service":"0xEB","instance":"0x1","unreliable":"30235","reliable":{"port":"30235","enable-magic-cookies":"false"}}, + {"service":"0xEC","instance":"0x1","unreliable":"30236","reliable":{"port":"30236","enable-magic-cookies":"false"}}, + {"service":"0xED","instance":"0x1","unreliable":"30237","reliable":{"port":"30237","enable-magic-cookies":"false"}}, + {"service":"0xEE","instance":"0x1","unreliable":"30238","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xEF","instance":"0x1","unreliable":"30239","reliable":{"port":"30239","enable-magic-cookies":"false"}}, + {"service":"0xF0","instance":"0x1","unreliable":"30240","reliable":{"port":"30240","enable-magic-cookies":"false"}}, + {"service":"0xF1","instance":"0x1","unreliable":"30241","reliable":{"port":"30241","enable-magic-cookies":"false"}}, + {"service":"0xF2","instance":"0x1","unreliable":"30242","reliable":{"port":"30242","enable-magic-cookies":"false"}}, + {"service":"0xF3","instance":"0x1","unreliable":"60000","reliable":{"port":"30243","enable-magic-cookies":"false"}}, + {"service":"0xF4","instance":"0x1","unreliable":"30244","reliable":{"port":"30244","enable-magic-cookies":"false"}}, + {"service":"0xF5","instance":"0x1","unreliable":"30245","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xF6","instance":"0x1","unreliable":"30246","reliable":{"port":"30246","enable-magic-cookies":"false"}}, + {"service":"0xF7","instance":"0x1","unreliable":"30247","reliable":{"port":"30247","enable-magic-cookies":"false"}}, + {"service":"0xF8","instance":"0x1","unreliable":"30248","reliable":{"port":"30248","enable-magic-cookies":"false"}}, + {"service":"0xF9","instance":"0x1","unreliable":"30249","reliable":{"port":"30249","enable-magic-cookies":"false"}}, + {"service":"0xFA","instance":"0x1","unreliable":"30250","reliable":{"port":"30250","enable-magic-cookies":"false"}}, + {"service":"0xFB","instance":"0x1","unreliable":"30251","reliable":{"port":"30251","enable-magic-cookies":"false"}}, + {"service":"0xFC","instance":"0x1","unreliable":"60000","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0xFD","instance":"0x1","unreliable":"30253","reliable":{"port":"30253","enable-magic-cookies":"false"}}, + {"service":"0xFE","instance":"0x1","unreliable":"30254","reliable":{"port":"30254","enable-magic-cookies":"false"}}, + {"service":"0xFF","instance":"0x1","unreliable":"30255","reliable":{"port":"30255","enable-magic-cookies":"false"}}, + {"service":"0x100","instance":"0x1","unreliable":"30256","reliable":{"port":"30256","enable-magic-cookies":"false"}}, + {"service":"0x101","instance":"0x1","unreliable":"30257","reliable":{"port":"30257","enable-magic-cookies":"false"}}, + {"service":"0x102","instance":"0x1","unreliable":"30258","reliable":{"port":"30258","enable-magic-cookies":"false"}}, + {"service":"0x103","instance":"0x1","unreliable":"30259","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x104","instance":"0x1","unreliable":"30260","reliable":{"port":"30260","enable-magic-cookies":"false"}}, + {"service":"0x105","instance":"0x1","unreliable":"60000","reliable":{"port":"30261","enable-magic-cookies":"false"}}, + {"service":"0x106","instance":"0x1","unreliable":"30262","reliable":{"port":"30262","enable-magic-cookies":"false"}}, + {"service":"0x107","instance":"0x1","unreliable":"30263","reliable":{"port":"30263","enable-magic-cookies":"false"}}, + {"service":"0x108","instance":"0x1","unreliable":"30264","reliable":{"port":"30264","enable-magic-cookies":"false"}}, + {"service":"0x109","instance":"0x1","unreliable":"30265","reliable":{"port":"30265","enable-magic-cookies":"false"}}, + {"service":"0x10A","instance":"0x1","unreliable":"30266","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x10B","instance":"0x1","unreliable":"30267","reliable":{"port":"30267","enable-magic-cookies":"false"}}, + {"service":"0x10C","instance":"0x1","unreliable":"30268","reliable":{"port":"30268","enable-magic-cookies":"false"}}, + {"service":"0x10D","instance":"0x1","unreliable":"30269","reliable":{"port":"30269","enable-magic-cookies":"false"}}, + {"service":"0x10E","instance":"0x1","unreliable":"60000","reliable":{"port":"30270","enable-magic-cookies":"false"}}, + {"service":"0x10F","instance":"0x1","unreliable":"30271","reliable":{"port":"30271","enable-magic-cookies":"false"}}, + {"service":"0x110","instance":"0x1","unreliable":"30272","reliable":{"port":"30272","enable-magic-cookies":"false"}}, + {"service":"0x111","instance":"0x1","unreliable":"30273","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x112","instance":"0x1","unreliable":"30274","reliable":{"port":"30274","enable-magic-cookies":"false"}}, + {"service":"0x113","instance":"0x1","unreliable":"30275","reliable":{"port":"30275","enable-magic-cookies":"false"}}, + {"service":"0x114","instance":"0x1","unreliable":"30276","reliable":{"port":"30276","enable-magic-cookies":"false"}}, + {"service":"0x115","instance":"0x1","unreliable":"30277","reliable":{"port":"30277","enable-magic-cookies":"false"}}, + {"service":"0x116","instance":"0x1","unreliable":"30278","reliable":{"port":"30278","enable-magic-cookies":"false"}}, + {"service":"0x117","instance":"0x1","unreliable":"60000","reliable":{"port":"30279","enable-magic-cookies":"false"}}, + {"service":"0x118","instance":"0x1","unreliable":"30280","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x119","instance":"0x1","unreliable":"30281","reliable":{"port":"30281","enable-magic-cookies":"false"}}, + {"service":"0x11A","instance":"0x1","unreliable":"30282","reliable":{"port":"30282","enable-magic-cookies":"false"}}, + {"service":"0x11B","instance":"0x1","unreliable":"30283","reliable":{"port":"30283","enable-magic-cookies":"false"}}, + {"service":"0x11C","instance":"0x1","unreliable":"30284","reliable":{"port":"30284","enable-magic-cookies":"false"}}, + {"service":"0x11D","instance":"0x1","unreliable":"30285","reliable":{"port":"30285","enable-magic-cookies":"false"}}, + {"service":"0x11E","instance":"0x1","unreliable":"30286","reliable":{"port":"30286","enable-magic-cookies":"false"}}, + {"service":"0x11F","instance":"0x1","unreliable":"30287","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x120","instance":"0x1","unreliable":"60000","reliable":{"port":"30288","enable-magic-cookies":"false"}}, + {"service":"0x121","instance":"0x1","unreliable":"30289","reliable":{"port":"30289","enable-magic-cookies":"false"}}, + {"service":"0x122","instance":"0x1","unreliable":"30290","reliable":{"port":"30290","enable-magic-cookies":"false"}}, + {"service":"0x123","instance":"0x1","unreliable":"30291","reliable":{"port":"30291","enable-magic-cookies":"false"}}, + {"service":"0x124","instance":"0x1","unreliable":"30292","reliable":{"port":"30292","enable-magic-cookies":"false"}}, + {"service":"0x125","instance":"0x1","unreliable":"30293","reliable":{"port":"30293","enable-magic-cookies":"false"}}, + {"service":"0x126","instance":"0x1","unreliable":"30294","reliable":{"port":"60000","enable-magic-cookies":"false"}}, + {"service":"0x127","instance":"0x1","unreliable":"30295","reliable":{"port":"30295","enable-magic-cookies":"false"}}, + {"service":"0x128","instance":"0x1","unreliable":"30296","reliable":{"port":"30296","enable-magic-cookies":"false"}}, + {"service":"0x129","instance":"0x1","unreliable":"60000","reliable":{"port":"30297","enable-magic-cookies":"false"}}, + {"service":"0x12A","instance":"0x1","unreliable":"30298","reliable":{"port":"30298","enable-magic-cookies":"false"}}, + {"service":"0x12B","instance":"0x1","unreliable":"30299","reliable":{"port":"30299","enable-magic-cookies":"false"}}, + {"service":"0x12C","instance":"0x1","unreliable":"30300","reliable":{"port":"30300","enable-magic-cookies":"false"}} + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "ttl" : "3", + "multicast":"224.0.11.1", + "cyclic_offer_delay" : "1000", + "port":"30490", + "protocol":"udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave_starter.sh.in new file mode 100755 index 00000000000..5587019a832 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_big_sd_msg_slave_starter.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 +# Rejecting offer for which there is already a remote offer: +# * start daemon +# * start application which offers service +# * start daemon remotely +# * start same application which offers the same service again remotely +# -> should be rejected as there is already a service instance +# running in the network + +export VSOMEIP_CONFIGURATION=offer_test_big_sd_msg_slave.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +sleep 1 +# Start the services +./offer_test_big_sd_msg_service & +PID_SERVICE_TWO=$! +sleep 1 + +# Wait until all clients and services are finished +for job in $PID_SERVICE_TWO +do + # Fail gets incremented if a client exits with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + + + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master.json.in new file mode 100644 index 00000000000..afe04b40b74 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master_starter.sh.in new file mode 100755 index 00000000000..4d30a805260 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_master_starter.sh.in @@ -0,0 +1,150 @@ +#!/bin/bash +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 +# Rejecting offer for which there is already a remote offer: +# * start daemon +# * start application which offers service +# * start daemon remotely +# * start same application which offers the same service again remotely +# -> should be rejected as there is already a service instance +# running in the network + +export VSOMEIP_CONFIGURATION=offer_test_external_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the services +./offer_test_service 2 & +PID_SERVICE_TWO=$! +echo "SERVICE_TWO pid $PID_SERVICE_TWO" + +./offer_test_client SUBSCRIBE & +CLIENT_PID_ONE=$! +echo "client pid ${CLIENT_PIDS}" + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/offer_tests; ./offer_test_external_slave_starter.sh\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && sleep 10; ./offer_test_external_slave_starter.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** offer_test_external_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** offer_test_external_master.json and +** offer_test_external_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +# Fail gets incremented if a client exits with a non-zero exit code +echo "waiting for $job" +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $PID_SERVICE_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# wait for slave to finish +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + echo "[Master] waiting for job $job" + wait $job || ((FAIL+=1)) +done + +# Rejecting remote offer for which there is already a local offer +# * start application which offers service +# * send sd message trying to offer the same service instance as already +# offered locally from a remote host + +export VSOMEIP_CONFIGURATION=offer_test_external_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the services +./offer_test_service 2 & +PID_SERVICE_TWO=$! + +./offer_test_client SUBSCRIBE & +CLIENT_PID_ONE=$! +echo "client pid ${CLIENT_PID_ONE}" + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_sd_msg_sender" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/offer_tests; ./offer_test_external_sd_msg_sender @TEST_IP_MASTER@\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && sleep 10; ./offer_test_external_sd_msg_sender @TEST_IP_MASTER@" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** offer_test_external_sd_msg_sender @TEST_IP_MASTER@ +** (pass the correct ip address of your test master) +** from an external host to successfully complete this test. +** +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +# Fail gets incremented if a client exits with a non-zero exit code +echo "waiting for $job" +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $PID_SERVICE_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# wait for slave to finish +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + echo "[Master] waiting for job $job" + wait $job || ((FAIL+=1)) +done + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave.json.in new file mode 100644 index 00000000000..cc70de94371 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave.json.in @@ -0,0 +1,36 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave_starter.sh.in new file mode 100755 index 00000000000..a70f1e4457d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_external_slave_starter.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 +# Rejecting offer for which there is already a remote offer: +# * start daemon +# * start application which offers service +# * start daemon remotely +# * start same application which offers the same service again remotely +# -> should be rejected as there is already a service instance +# running in the network + +export VSOMEIP_CONFIGURATION=offer_test_external_slave.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +sleep 1 +# Start the services +./offer_test_service_external 2 & +PID_SERVICE_TWO=$! +sleep 1 + +# Wait until all clients and services are finished +for job in $PID_SERVICE_TWO +do + # Fail gets incremented if a client exits with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + + + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local.json.in new file mode 100644 index 00000000000..8768440404b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local.json.in @@ -0,0 +1,19 @@ +{ + "unicast":"127.0.0.1", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"false" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local_starter.sh.in new file mode 100755 index 00000000000..85ffc23d156 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_local_starter.sh.in @@ -0,0 +1,278 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running first test +******************************************************************************* +******************************************************************************* +End-of-message + +# Rejecting offer of service instance whose hosting application is still +# alive: +# * start application which offers service +# * start two clients which continuously exchanges messages with the service +# * start application which offers the same service again -> should be +# rejected and an error message should be printed. +# * Message exchange with client application should not be interrupted. + +export VSOMEIP_CONFIGURATION=offer_test_local.json +# Start the services +./offer_test_service 1 & +PID_SERVICE_ONE=$! +./offer_test_client SUBSCRIBE & +CLIENT_PID_ONE=$! +./offer_test_client SUBSCRIBE & +CLIENT_PID_TWO=$! + +./offer_test_service 2 & +PID_SERVICE_TWO=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill $PID_SERVICE_TWO +kill $PID_SERVICE_ONE +sleep 1 + + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running second test +******************************************************************************* +******************************************************************************* +End-of-message + +# Rejecting offer of service instance whose hosting application is still +# alive with daemon: +# * start daemon (needed as he has to ping the offering client) +# * start application which offers service +# * start two clients which continuously exchanges messages with the service +# * start application which offers the same service again -> should be +# rejected and an error message should be printed. +# * Message exchange with client application should not be interrupted. + +export VSOMEIP_CONFIGURATION=offer_test_local.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +# Start the services +./offer_test_service 2 & +PID_SERVICE_TWO=$! +./offer_test_client SUBSCRIBE & +CLIENT_PID_ONE=$! +./offer_test_client SUBSCRIBE & +CLIENT_PID_TWO=$! + +./offer_test_service 3 & +PID_SERVICE_THREE=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill $PID_SERVICE_THREE +kill $PID_SERVICE_TWO +sleep 1 +kill $PID_VSOMEIPD +sleep 1 + + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running third test +******************************************************************************* +******************************************************************************* +End-of-message + +# Accepting offer of service instance whose hosting application crashed +# with (send SIGKILL) +# * start daemon +# * start application which offers service +# * start client which exchanges messages with the service +# * kill application with SIGKILL +# * start application which offers the same service again -> should be +# accepted. +# * start another client which exchanges messages with the service +# * Client should now communicate with new offerer. + +export VSOMEIP_CONFIGURATION=offer_test_local.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the service +./offer_test_service 2 & +PID_SERVICE_TWO=$! + +# Start a client +./offer_test_client METHODCALL & +CLIENT_PID_ONE=$! + +# Kill the service +sleep 1 +kill -KILL $PID_SERVICE_TWO + +# reoffer the service +./offer_test_service 3 & +PID_SERVICE_THREE=$! + +# Start another client +./offer_test_client METHODCALL & +CLIENT_PID_TWO=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill $PID_SERVICE_THREE +kill $PID_VSOMEIPD +sleep 1 + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running fourth test +******************************************************************************* +******************************************************************************* +End-of-message + +# Accepting offer of service instance whose hosting application became +# unresponsive (SIGSTOP) +# * start daemon +# * start application which offers service +# * Send a SIGSTOP to the service to make it unresponsive +# * start application which offers the same service again -> should be +# marked as PENDING_OFFER and a ping should be sent to the paused +# application. +# * After the timeout passed the new offer should be accepted. +# * start client which exchanges messages with the service +# * Client should now communicate with new offerer. + +export VSOMEIP_CONFIGURATION=offer_test_local.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the service +./offer_test_service 2 & +PID_SERVICE_TWO=$! + +# Start a client +./offer_test_client METHODCALL & +CLIENT_PID_ONE=$! + +# Pause the service +sleep 1 +kill -STOP $PID_SERVICE_TWO + +# reoffer the service +./offer_test_service 3 & +PID_SERVICE_THREE=$! + +# Start another client +./offer_test_client METHODCALL & +CLIENT_PID_TWO=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill -CONT $PID_SERVICE_TWO +kill $PID_SERVICE_TWO +kill $PID_SERVICE_THREE +kill $PID_VSOMEIPD +sleep 1 + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running fifth test +******************************************************************************* +******************************************************************************* +End-of-message + +# Rejecting offers for which there is already a pending offer +# * start daemon +# * start application which offers service +# * Send a SIGSTOP to the service to make it unresponsive +# * start application which offers the same service again -> should be +# marked as PENDING_OFFER and a ping should be sent to the paused +# application. +# * start application which offers the same service again -> should be +# rejected as there is already a PENDING_OFFER pending. +# * After the timeout passed the new offer should be accepted. +# * start client which exchanges messages with the service +# * Client should now communicate with new offerer. + +export VSOMEIP_CONFIGURATION=offer_test_local.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the service +./offer_test_service 2 & +PID_SERVICE_TWO=$! + +# Start a client +./offer_test_client METHODCALL & +CLIENT_PID_ONE=$! + +# Pause the service +sleep 1 +kill -STOP $PID_SERVICE_TWO + +# reoffer the service +./offer_test_service 3 & +PID_SERVICE_THREE=$! + +# reoffer the service again to provoke rejecting as there is +# already a pending offer +./offer_test_service 4 & +PID_SERVICE_FOUR=$! + +# Start another client +./offer_test_client METHODCALL & +CLIENT_PID_TWO=$! + +# Wait until all clients are finished +# Fail gets incremented if a client exits with a non-zero exit code +wait $CLIENT_PID_ONE || FAIL=$(($FAIL+1)) +wait $CLIENT_PID_TWO || FAIL=$(($FAIL+1)) + +# kill the services +kill -CONT $PID_SERVICE_TWO +kill $PID_SERVICE_TWO +kill $PID_SERVICE_THREE +kill $PID_SERVICE_FOUR +kill $PID_VSOMEIPD + + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings.json.in new file mode 100644 index 00000000000..07a467727fe --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings.json.in @@ -0,0 +1,25 @@ +{ + "logging": { + "level": "verbose", + "console": "true", + "file": { + "enable": "false" + }, + "dlt": "false" + }, + "applications": [ + { + "name": "daemon", + "id": "0x0001" + }, + { + "name": "service", + "id": "0x0002" + }, + { + "name": "client", + "id": "0x0004" + } + ], + "routing": "daemon" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings_starter.sh.in new file mode 100755 index 00000000000..86acd393c3d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/conf/offer_test_multiple_offerings_starter.sh.in @@ -0,0 +1,14 @@ +#!/bin/bash + +FAIL=0 +# Start the application +# Note: Every service (daemon, services, client) are per-thread in this executable + +export VSOMEIP_CONFIGURATION=offer_test_multiple_offerings.json + +if ! ./offer_test_multiple_offerings +then + ((FAIL+=1)) +fi + +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_client.cpp new file mode 100644 index 00000000000..91a5b1f1200 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_client.cpp @@ -0,0 +1,241 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "offer_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class offer_test_big_sd_msg_client : public vsomeip_utilities::base_logger { +public: + offer_test_big_sd_msg_client(struct offer_test::service_info _service_info) : + vsomeip_utilities::base_logger("OTBC", "OFFER TEST BIG SD MSG CLIENT"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("offer_test_big_sd_msg_client")), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_until_subscribed_(true), + wait_for_stop_(true), + stop_thread_(std::bind(&offer_test_big_sd_msg_client::wait_for_stop, this)), + send_thread_(std::bind(&offer_test_big_sd_msg_client::send, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_big_sd_msg_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&offer_test_big_sd_msg_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, + std::bind(&offer_test_big_sd_msg_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), 0x1, 0x1); + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(offer_test::big_msg_eventgroup_id); + for (std::uint16_t s = 1; s <= offer_test::big_msg_number_services; s++) { + app_->request_service(s,0x1,0x1,0x1); + app_->request_event(s,0x1, offer_test::big_msg_event_id, + its_eventgroups, vsomeip::event_type_e::ET_EVENT, + vsomeip::reliability_type_e::RT_UNKNOWN); + app_->subscribe(s, 0x1,offer_test::big_msg_eventgroup_id, 0x1, + offer_test::big_msg_event_id); + services_available_subribed_[s] = std::make_pair(false,0); + app_->register_subscription_status_handler(s,0x1, + offer_test::big_msg_eventgroup_id, + offer_test::big_msg_event_id, + std::bind(&offer_test_big_sd_msg_client::subscription_status_changed, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + } + app_->start(); + } + + ~offer_test_big_sd_msg_client() { + send_thread_.join(); + stop_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_WARNING << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_DEBUG << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + + std::lock_guard<std::mutex> its_lock(mutex_); + if(_is_available) { + auto found_service = services_available_subribed_.find(_service); + if (found_service != services_available_subribed_.end()) { + found_service->second.first = true; + if (std::all_of(services_available_subribed_.cbegin(), + services_available_subribed_.cend(), + [](const services_available_subribed_t::value_type& v) { + return v.second.first; + } + )) { + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "All services available!"; + VSOMEIP_WARNING << "************************************************************"; + wait_until_service_available_ = false; + condition_.notify_one(); + } + } + } + } + + void subscription_status_changed(const vsomeip::service_t _service, + const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, + const vsomeip::event_t _event, + const uint16_t _error) { + EXPECT_EQ(0x1, _instance); + EXPECT_EQ(offer_test::big_msg_eventgroup_id, _eventgroup); + EXPECT_EQ(offer_test::big_msg_event_id, _event); + VSOMEIP_DEBUG << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] has " << (!_error ? "sent subscribe ack":" sent subscribe_nack") << "."; + if (_error == 0x0 /*OK*/) { + + std::lock_guard<std::mutex> its_lock(mutex_); + auto found_service = services_available_subribed_.find(_service); + if (found_service != services_available_subribed_.end()) { + found_service->second.second++; + if (found_service->second.second > 1) { + ADD_FAILURE() << "Registered subscription status handler was " + "called " << std::dec << found_service->second.second + << " times for service: " << std::hex + << found_service->first; + } + if (std::all_of(services_available_subribed_.cbegin(), + services_available_subribed_.cend(), + [](const services_available_subribed_t::value_type& v) { + return v.second.second == 1; + } + )) { + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "All subscription were acknowledged!"; + VSOMEIP_WARNING << "************************************************************"; + wait_until_subscribed_ = false; + condition_.notify_one(); + } + } + } + }; + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if (_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + on_response(_message); + } + } + + void on_response(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(0x1, _message->get_service()); + EXPECT_EQ(service_info_.shutdown_method_id, _message->get_method()); + EXPECT_EQ(0x1, _message->get_instance()); + if(service_info_.shutdown_method_id == _message->get_method()) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + VSOMEIP_INFO << "going down"; + stop_condition_.notify_one(); + } + } + + void send() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + while (wait_until_service_available_) { + condition_.wait(its_lock); + } + + while (wait_until_subscribed_) { + condition_.wait(its_lock); + } + + std::this_thread::sleep_for(std::chrono::seconds(5)); + std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request(); + its_req->set_service(1); + its_req->set_instance(1); + its_req->set_interface_version(0x1); + its_req->set_method(service_info_.shutdown_method_id); + app_->send(its_req); + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + +private: + struct offer_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + bool wait_until_subscribed_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + + typedef std::map<vsomeip::service_t,std::pair<bool, std::uint32_t>> services_available_subribed_t; + services_available_subribed_t services_available_subribed_; + std::thread stop_thread_; + std::thread send_thread_; +}; + +TEST(someip_offer_test_big_sd_msg, subscribe_or_call_method_at_service) +{ + offer_test_big_sd_msg_client its_sample(offer_test::service); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_service.cpp new file mode 100644 index 00000000000..b83870ba941 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_big_sd_msg_service.cpp @@ -0,0 +1,175 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <algorithm> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "offer_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class offer_test_big_sd_msg_service : public vsomeip_utilities::base_logger { +public: + offer_test_big_sd_msg_service(struct offer_test::service_info _service_info) : + vsomeip_utilities::base_logger("OTBS", "OFFER TEST BIG SD MSG SERVICE"), + service_info_(_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application("offer_test_big_sd_msg_service")), + wait_until_registered_(true), + wait_until_client_subscribed_to_all_services_(true), + shutdown_method_called_(false), + offer_thread_(std::bind(&offer_test_big_sd_msg_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_big_sd_msg_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(offer_test::big_msg_eventgroup_id); + for (std::uint16_t s = 1; s <= offer_test::big_msg_number_services; s++) { + app_->offer_event(s, 0x1, + offer_test::big_msg_event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN); + app_->register_subscription_handler(s, 0x1, offer_test::big_msg_eventgroup_id, + std::bind(&offer_test_big_sd_msg_service::on_subscription, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, s)); + subscriptions_[s] = 0; + } + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&offer_test_big_sd_msg_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + + app_->start(); + } + + ~offer_test_big_sd_msg_service() { + offer_thread_.join(); + } + + void offer() { + for (std::uint16_t s = 1; s <= offer_test::big_msg_number_services; s++) { + app_->offer_service(s,0x1,0x1,0x1); + } + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + bool on_subscription(vsomeip::client_t _client, + std::uint32_t _uid, std::uint32_t _gid, + bool _subscribed, + vsomeip::service_t _service) { + (void)_client; + (void)_uid; + (void)_gid; + if (_subscribed) { + subscriptions_[_service]++; + EXPECT_EQ(1u, subscriptions_[_service]); + if (std::all_of(subscriptions_.begin(), subscriptions_.end(), [&](const subscriptions_t::value_type& v){ + return v.second == 1; + })) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_client_subscribed_to_all_services_ = false; + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Client subscribed to all services!"; + VSOMEIP_WARNING << "************************************************************"; + condition_.notify_one(); + } + } + + return true; + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + std::this_thread::sleep_for(std::chrono::seconds(1)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + shutdown_method_called_ = true; + for (std::uint16_t s = 1; s <= offer_test::big_msg_number_services; s++) { + app_->stop_offer_service(s,0x1,0x1,0x1); + } + app_->clear_all_handler(); + app_->stop(); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_until_client_subscribed_to_all_services_) { + condition_.wait(its_lock); + } + } + +private: + struct offer_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_client_subscribed_to_all_services_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> shutdown_method_called_; + typedef std::map<vsomeip::service_t, std::uint32_t> subscriptions_t; + subscriptions_t subscriptions_; + std::thread offer_thread_; +}; + +TEST(someip_offer_test_big_sd_msg, notify_increasing_counter) +{ + offer_test_big_sd_msg_service its_sample(offer_test::service); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_client.cpp new file mode 100644 index 00000000000..e5697cb2fd6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_client.cpp @@ -0,0 +1,291 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef ANDROID +#include "../../implementation/configuration/include/internal_android.hpp" +#else +#include "../../implementation/configuration/include/internal.hpp" +#endif // ANDROID + +#include "offer_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +enum operation_mode_e { + SUBSCRIBE, + METHODCALL +}; + +class offer_test_client : public vsomeip_utilities::base_logger { +public: + offer_test_client(struct offer_test::service_info _service_info, operation_mode_e _mode) : + vsomeip_utilities::base_logger("OTC1", "OFFER TEST CLIENT"), + service_info_(_service_info), + operation_mode_(_mode), + app_(vsomeip::runtime::get()->create_application("offer_test_client")), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_for_stop_(true), + last_received_counter_(0), + last_received_response_(std::chrono::steady_clock::now()), + number_received_responses_(0), + stop_thread_(std::bind(&offer_test_client::wait_for_stop, this)), + send_thread_(std::bind(&offer_test_client::send, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&offer_test_client::on_message, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&offer_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(service_info_.service_id, + service_info_.instance_id); + + if (operation_mode_ == operation_mode_e::SUBSCRIBE) { + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->request_event(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + its_eventgroups, vsomeip::event_type_e::ET_EVENT, + vsomeip::reliability_type_e::RT_BOTH); + + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.eventgroup_id, vsomeip::DEFAULT_MAJOR); + } + + app_->start(); + } + + ~offer_test_client() { + send_thread_.join(); + stop_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + std::lock_guard<std::mutex> its_lock(mutex_); + if(_is_available) { + wait_until_service_available_ = false; + condition_.notify_one(); + } else { + wait_until_service_available_ = true; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + on_notification(_message); + } else if (_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + on_response(_message); + } + } + + void on_notification(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::payload> its_payload(_message->get_payload()); + EXPECT_EQ(4u, its_payload->get_length()); + vsomeip::byte_t *d = its_payload->get_data(); + static std::uint32_t number_received_notifications(0); + std::uint32_t counter(0); + counter |= static_cast<std::uint32_t>(d[0] << 24); + counter |= static_cast<std::uint32_t>(d[0] << 16); + counter = counter | static_cast<std::uint32_t>((d[2] << 8)); + counter = counter | static_cast<std::uint32_t>(d[3]); + + VSOMEIP_DEBUG + << "Received a notification with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "] got:" << std::dec << counter; + + ASSERT_GT(counter, last_received_counter_); + last_received_counter_ = counter; + ++number_received_notifications; + + if(number_received_notifications >= 250) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + VSOMEIP_INFO << "going down"; + stop_condition_.notify_one(); + } + } + + void on_response(const std::shared_ptr<vsomeip::message> &_message) { + ++number_received_responses_; + static bool first(true); + if (first) { + first = false; + last_received_response_ = std::chrono::steady_clock::now(); + return; + } + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::steady_clock::now() - last_received_response_).count(), + (std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT) + + std::chrono::milliseconds(1000)).count()); + last_received_response_ = std::chrono::steady_clock::now(); + std::cout << "."; + std::cout.flush(); + } + + void send() { + if (operation_mode_ != operation_mode_e::METHODCALL) { + return; + } + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + while (wait_until_service_available_) { + condition_.wait(its_lock); + } + its_lock.unlock(); + its_lock.release(); + + for (int var = 0; var < offer_test::number_of_messages_to_send; ++var) { + bool send(false); + { + std::lock_guard<std::mutex> its_lock(mutex_); + send = !wait_until_service_available_; + } + if (send) { + std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request(); + its_req->set_service(service_info_.service_id); + its_req->set_instance(service_info_.instance_id); + its_req->set_method(service_info_.method_id); + app_->send(its_req); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + VSOMEIP_INFO << "going down. Sent " << offer_test::number_of_messages_to_send + << " requests and received " << number_received_responses_ + << " responses"; + stop_condition_.notify_one(); + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + +private: + struct offer_test::service_info service_info_; + operation_mode_e operation_mode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + + std::uint32_t last_received_counter_; + std::chrono::steady_clock::time_point last_received_response_; + std::atomic<std::uint32_t> number_received_responses_; + std::thread stop_thread_; + std::thread send_thread_; +}; + +static operation_mode_e passed_mode = operation_mode_e::SUBSCRIBE; + +TEST(someip_offer_test, subscribe_or_call_method_at_service) +{ + offer_test_client its_sample(offer_test::service, passed_mode); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl; + return 1; + } + + if (std::string("SUBSCRIBE") == std::string(argv[1])) { + passed_mode = operation_mode_e::SUBSCRIBE; + } else if (std::string("METHODCALL") == std::string(argv[1])) { + passed_mode = operation_mode_e::METHODCALL; + } else { + std::cerr << "Wrong operation mode passed, exiting" << std::endl; + std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl; + return 1; + } + +#if 0 + if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) { + use_same_service_id = true; + } else { + use_same_service_id = false; + } +#endif + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_external_sd_msg_sender.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_external_sd_msg_sender.cpp new file mode 100644 index 00000000000..fa57d51a810 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_external_sd_msg_sender.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <exception> +#include <iostream> + +#include <gtest/gtest.h> + +#include <boost/asio.hpp> + +static char* passed_address; + +TEST(someip_offer_test, send_offer_service_sd_message) +{ + try { + boost::asio::io_context io; + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(passed_address)), + 30490); + boost::asio::ip::udp::socket udp_socket(io, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, + 0x01, 0x00, 0x00, 0x20, + 0x11, 0x11, 0x00, 0x01, + 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, + 0x00, 0x09, 0x04, 0x00, + 0x0a, 0x00, 0x03, 0x01, + 0x00, 0x06, 0x9c, 0x41, + 0x00, 0x09, 0x04, 0x00, + 0x0a, 0x00, 0x03, 0x7D, // slave address + 0x00, 0x11, 0x75, 0x31 + }; + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_offer_service_message), target_sd); + ++its_offer_service_message[11]; + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x11, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(passed_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (const std::exception& e) { + std::cerr << "Caught exception: " << e.what() << '\n'; + ASSERT_FALSE(true); + } +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cout << "Please pass an target IP address to this binary like: " + << argv[0] << " 10.0.3.1" << std::endl; + exit(1); + } + passed_address = argv[1]; + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_globals.hpp new file mode 100644 index 00000000000..ba698869958 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_globals.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef OFFER_TEST_GLOBALS_HPP_ +#define OFFER_TEST_GLOBALS_HPP_ + +namespace offer_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; +}; + +struct service_info service = { 0x1111, 0x1, 0x1111, 0x1111, 0x1000, 0x1404 }; + +static constexpr int number_of_messages_to_send = 150; + +static constexpr std::uint16_t big_msg_number_services = 300; +static constexpr vsomeip::event_t big_msg_event_id = 0x8000; +static constexpr vsomeip::eventgroup_t big_msg_eventgroup_id = 0x1; +} + +#endif /* OFFER_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_multiple_offerings.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_multiple_offerings.cpp new file mode 100644 index 00000000000..c25e5233b43 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_multiple_offerings.cpp @@ -0,0 +1,298 @@ +#include <atomic> +#include <chrono> +#include <condition_variable> +#include <gtest/gtest.h> +#include <iomanip> +#include <iostream> +#include <map> +#include <mutex> +#include <sstream> +#include <string> +#include <thread> +#include <unistd.h> +#include <vector> +#include <vsomeip/internal/logger.hpp> + +#include <vsomeip/vsomeip.hpp> + +using namespace vsomeip; +using namespace std::chrono_literals; + +constexpr auto TIMEOUT_RESPONSE = 1000ms; +constexpr auto REQUESTS_NUMBER = 10; + +class common { +public: + virtual void on_availability(service_t _service_id, instance_t _instance_id, bool _is_available); + +public: + instance_t instance_id_; + service_t service_id_; + major_version_t major_version_; + minor_version_t minor_version_; + std::shared_ptr<application> app_; + std::thread thread_id_; + std::condition_variable condition_availability_; + std::atomic_bool availability_; + std::atomic_bool msg_sent_; +}; + +void common::on_availability(service_t _service_id, instance_t _instance_id, bool _is_available) { + if (_service_id == service_id_ && _instance_id == instance_id_) { + if (_is_available) { + // NOTE: Using the most strict memory ordering operation. + // Refer to https://en.cppreference.com/w/cpp/atomic/memory_order for possible options + availability_.store(true); + condition_availability_.notify_one(); + } else { + availability_.store(false); + } + } +} + +class client : common { +public: + client(service_t _service_id, + instance_t _instance_id, + major_version_t _major_version, + minor_version_t _minor_version) { + service_id_ = _service_id; + instance_id_ = _instance_id; + major_version_ = _major_version; + minor_version_ = _minor_version; + + app_ = runtime::get()->create_application("client"); + app_->init(); + app_->register_availability_handler(service_id_, instance_id_, + std::bind(&client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_message_handler( + service_id_, instance_id_, ANY_METHOD, + std::bind(&client::on_message, this, std::placeholders::_1)); + app_->request_service(service_id_, instance_id_, major_version_, minor_version_); + + thread_id_ = std::thread(std::bind(&client::run, this)); + } + + void run() { + app_->start(); + } + + bool was_message_received() { + std::unique_lock<std::mutex> lock(mutex_); + condition_message_received_.wait(lock, [=] { return message_received_.load(); }); + return message_received_.load(); + } + + std::vector<uint8_t> getReceivedPayload() { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + return received_payload_; + } + + bool wait_availability() { + std::unique_lock<std::mutex> lock(mutex_); + condition_availability_.wait(lock, [=] { return availability_.load(); }); + return availability_.load(); + } + + void send_message(const std::vector<uint8_t>& _outgoing_payload) { + msg_sent_.store(false); + auto request = runtime::get()->create_request(); + request->set_service(service_id_); + request->set_instance(instance_id_); + request->set_method(1); + + request->set_payload(runtime::get()->create_payload(_outgoing_payload)); + app_->send(request); + + std::unique_lock<std::mutex> lock(mutex_); + condition_message_sent_.wait(lock, [=] { return msg_sent_.load(); }); + } + + ~client() { + app_->stop(); + thread_id_.join(); + } + +private: + void on_availability(service_t _service_id, instance_t _instance_id, bool _is_available) { + common::on_availability(_service_id, _instance_id, _is_available); + } + + void on_message(const std::shared_ptr<message>& _message) { + auto its_payload = _message->get_payload(); + auto const len = its_payload->get_length(); + + std::stringstream msg; + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + received_payload_.clear(); + for (uint32_t i = 0; i < len; ++i) { + received_payload_.push_back(*(its_payload->get_data() + i)); + msg << std::hex << std::setw(2) << std::setfill('0') << (int)(*(its_payload->get_data() + i)) << " "; + } + } + + VSOMEIP_INFO << "[TEST] Got message from " + << std::hex << std::setw(4) << std::setfill('0') << _message->get_service() << "." + << std::hex << std::setw(4) << std::setfill('0') << _message->get_instance() + << " length " << std::dec << len << " and payload " << msg.str(); + { + std::lock_guard<std::mutex> its_lock(mutex_); + msg_sent_.store(true); + condition_message_sent_.notify_one(); + } + + std::lock_guard<std::mutex> its_lock(mutex_); + if (_message->get_service() == service_id_ && _message->get_instance() == instance_id_) { + message_received_.store(true); + condition_message_received_.notify_one(); + } else { + message_received_.store(false); + } + } + +private: + std::condition_variable condition_message_received_; + std::condition_variable condition_message_sent_; + std::mutex mutex_; + + std::atomic_bool message_received_; + + std::vector<uint8_t> received_payload_; + std::mutex payload_mutex_; +}; + +class server : common { +public: + server(service_t _service_id, instance_t _instance_id, major_version_t _major_version, + minor_version_t _minor_version) { + service_id_ = _service_id; + instance_id_ = _instance_id; + major_version_ = _major_version; + minor_version_ = _minor_version; + + app_ = runtime::get()->create_application("service"); + app_->init(); + + app_->register_availability_handler(service_id_, instance_id_, + std::bind(&server::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->register_message_handler( + service_id_, instance_id_, ANY_METHOD, + std::bind(&server::on_message, this, std::placeholders::_1)); + app_->offer_service(service_id_, instance_id_, major_version_, minor_version_); + app_->request_service(service_id_, instance_id_, major_version_, minor_version_); + + thread_id_ = std::thread(std::bind(&server::run, this)); + } + + void run() { app_->start(); } + + bool is_available() { return app_->is_available(service_id_, instance_id_); } + + bool wait_availability() { + std::unique_lock<std::mutex> lock(mutex_); + condition_availability_.wait(lock, [=] { return availability_.load(); }); + return availability_.load(); + } + + ~server() { + app_->stop(); + thread_id_.join(); + } + +private: + void on_message(const std::shared_ptr<message>& _message) { + const vsomeip::length_t len = _message->get_payload()->get_length(); + std::vector<uint8_t> out_payload; + std::stringstream msg; + for (uint32_t i = 0; i < len; ++i) { + out_payload.push_back(*(_message->get_payload()->get_data() + i)); + msg << std::hex << std::setw(2) << std::setfill('0') << (int)(*(_message->get_payload()->get_data() + i)) << " "; + } + std::shared_ptr<vsomeip::message> response = runtime::get()->create_response(_message); + response->set_payload(vsomeip::runtime::get()->create_payload(out_payload)); + + VSOMEIP_INFO << "[TEST] Sending " << msg.str(); + app_->send(response); + } + + void on_availability(service_t _service_id, instance_t _instance_id, bool _is_available) { + common::on_availability(_service_id, _instance_id, _is_available); + } + +private: + std::mutex mutex_; +}; + +class vsomeip_daemon { +public: + vsomeip_daemon() { + app_ = vsomeip::runtime::get()->create_application("daemon"); + app_->init(); + run_daemon_thread_ = std::thread(std::bind(&vsomeip_daemon::run, this)); + } + + void set_routing_state(routing_state_e state) { app_->set_routing_state(state); } + + ~vsomeip_daemon() { + app_->stop(); + run_daemon_thread_.join(); + } +private: + void run() { app_->start(); } +private: + std::shared_ptr<application> app_; + std::thread run_daemon_thread_; +}; + +TEST(offer_test, multiple_offerings_same_service) +{ + const service_t service_id { 0xfee2 }; + const instance_t instance_id { 0x0001 }; + const major_version_t major { 1 }; + const minor_version_t minor { 0 }; + + vsomeip_daemon daemon; + + server service_1(service_id, instance_id, major, minor); + service_1.wait_availability(); + VSOMEIP_INFO << "[TEST] Service 1 is AVAILABLE"; + + server service_2(service_id, instance_id, major, minor); + service_2.wait_availability(); + VSOMEIP_INFO << "[TEST] Service 2 is AVAILABLE"; + + client client(service_id, instance_id, major, minor); + client.wait_availability(); + VSOMEIP_INFO << "[TEST] Client is AVAILABLE"; + + // Without suspending the deamon, the client immediatly closes. + daemon.set_routing_state(routing_state_e::RS_SUSPENDED); + + for (int i = 0; i < REQUESTS_NUMBER; ++i) { + VSOMEIP_INFO << "[TEST] Sending Loop " << i; + // NOTE: Don't remove the sleep. VSOME/IP needs some time until it sends a PONG message to + // services. Otherwise we can't detect service availability correctly later. + std::this_thread::sleep_for(TIMEOUT_RESPONSE); + std::vector<uint8_t> out_payload = { uint8_t(i) }; + client.send_message(out_payload); + // Independant of the number of offerings, the client must never fail it's assertions. + ASSERT_TRUE(client.was_message_received()) << "Message was not received"; + // Should be safe to read the payload without locks. No one is reading or writing to it. + EXPECT_EQ(out_payload, client.getReceivedPayload()) << "Payload was not equal"; + } + // Both offerings must be available after the client is done. + // Failing this availability test means one of the instances has crashed. + ASSERT_TRUE(service_1.is_available()); + ASSERT_TRUE(service_2.is_available()); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service.cpp new file mode 100644 index 00000000000..5fa5c123432 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service.cpp @@ -0,0 +1,174 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "offer_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +static std::string service_number; + +class offer_test_service : public vsomeip_utilities::base_logger { +public: + offer_test_service(struct offer_test::service_info _service_info) : + vsomeip_utilities::base_logger("OTS1", "OFFER TEST SERVICE"), + service_info_(_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application( + (service_number == "1") ? "routingmanagerd" : + "offer_test_service" + service_number)), + counter_(0), + wait_until_registered_(true), + shutdown_method_called_(false), + offer_thread_(std::bind(&offer_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_BOTH); + + inc_counter_and_notify(); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&offer_test_service::on_request, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&offer_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + app_->start(); + } + + ~offer_test_service() { + offer_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + // this is allowed + app_->offer_service(service_info_.service_id, service_info_.instance_id); + // this is not allowed and will be rejected + app_->offer_service(service_info_.service_id, service_info_.instance_id, 33, 4711); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + shutdown_method_called_ = true; + // this is will trigger a warning + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id, 44, 4711); + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + app_->clear_all_handler(); + app_->stop(); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Notifying"; + while(!shutdown_method_called_) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + inc_counter_and_notify(); + } + } + + void inc_counter_and_notify() { + ++counter_; + // set value to field + const std::shared_ptr<vsomeip::payload> its_payload(vsomeip::runtime::get()->create_payload()); + std::vector<vsomeip::byte_t> its_data; + its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF000000) >> 24)); + its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF0000) >> 16)); + its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF00) >> 8)); + its_data.push_back(static_cast<vsomeip::byte_t>((counter_ & 0xFF))); + its_payload->set_data(its_data); + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + } + +private: + struct offer_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + std::uint32_t counter_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> shutdown_method_called_; + std::thread offer_thread_; +}; + +TEST(someip_offer_test, notify_increasing_counter) +{ + offer_test_service its_sample(offer_test::service); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl; + return 1; + } + + service_number = std::string(argv[1]); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service_external.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service_external.cpp new file mode 100644 index 00000000000..d4c8c1d1f2c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offer_tests/offer_test_service_external.cpp @@ -0,0 +1,158 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../someip_test_globals.hpp" +#include "offer_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +static std::string service_number; + +class offer_test_service : public vsomeip_utilities::base_logger { +public: + offer_test_service(struct offer_test::service_info _service_info) : + vsomeip_utilities::base_logger("OTSE", "OFFER TEST SERVICE EXTERNAL"), + service_info_(_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application( + (service_number == "1") ? "routingmanagerd" : + "offer_test_service" + service_number)), + wait_until_registered_(true), + wait_until_service_available_(true), + offer_thread_(std::bind(&offer_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_service::on_state, this, + std::placeholders::_1)); + + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&offer_test_service::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->request_service(service_info_.service_id, + service_info_.instance_id); + app_->start(); + } + + ~offer_test_service() { + offer_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + // this is allowed + app_->offer_service(service_info_.service_id, service_info_.instance_id); + // this is not allowed and will be rejected + app_->offer_service(service_info_.service_id, service_info_.instance_id, 33, 4711); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + std::lock_guard<std::mutex> its_lock(mutex_); + if(_is_available) { + wait_until_service_available_ = false; + condition_.notify_one(); + } else { + wait_until_service_available_ = true; + condition_.notify_one(); + } + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while(wait_until_service_available_) { + condition_.wait(its_lock); + } + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Calling stop method"; + std::shared_ptr<vsomeip::message> msg(vsomeip::runtime::get()->create_request()); + msg->set_service(service_info_.service_id); + msg->set_instance(service_info_.instance_id); + msg->set_method(service_info_.shutdown_method_id); + msg->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + app_->send(msg); + std::this_thread::sleep_for(std::chrono::seconds(2)); + app_->clear_all_handler(); + app_->stop(); + } + +private: + struct offer_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; +}; + +TEST(someip_offer_test, notify_increasing_counter) +{ + offer_test_service its_sample(offer_test::service); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl; + return 1; + } + + service_number = std::string(argv[1]); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/CMakeLists.txt new file mode 100644 index 00000000000..ac0621ed251 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(offered_services_info_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + offered_services_info_test_local.json + offered_services_info_test_local_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(offered_services_info_test_service + offered_services_info_test_service.cpp +) + +# Add test executable. +add_executable(offered_services_info_test_client + offered_services_info_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + offered_services_info_test_service + offered_services_info_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME offered_services_info_test_local + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/offered_services_info_test_local_starter.sh + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local.json.in new file mode 100644 index 00000000000..42caa3504a9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local.json.in @@ -0,0 +1,57 @@ +{ + "unicast" : "127.0.0.1", + "diagnosis":"0x12", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "offered_services_info_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1111", + "instance" : "0x1" + }, + { + "service" : "0x2222", + "instance" : "0x2", + "reliable" : { "port" : "30502" }, + "unreliable" : "31002" + }, + { + "service" : "0x2223", + "instance" : "0x3", + "reliable" : { "port" : "30503" } + }, + { + "service" : "0x2224", + "instance" : "0x4", + "unreliable" : "31004" + } + ], + + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local_starter.sh.in new file mode 100755 index 00000000000..50047db892f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/conf/offered_services_info_test_local_starter.sh.in @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Running first test +******************************************************************************* +******************************************************************************* +End-of-message + +# Rejecting offer of service instance whose hosting application is still +# alive: +# * start application which offers service +# * start two clients which continuously exchanges messages with the service +# * start application which offers the same service again -> should be +# rejected and an error message should be printed. +# * Message exchange with client application should not be interrupted. + +# Array for client pids +CLIENT_PIDS=() +export VSOMEIP_CONFIGURATION=offered_services_info_test_local.json +# Start the services (routingmanagerd as app name) +./offered_services_info_test_service 1 & #routingmanagerd as app name +PID_SERVICE_ONE=$! +./offered_services_info_test_client METHODCALL & +CLIENT_PIDS+=($!) + +# Wait until all clients are finished +for job in ${CLIENT_PIDS[*]} +do + # Fail gets incremented if a client exits with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_SERVICE_ONE +sleep 1 + + +# Check if everything went well +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_client.cpp new file mode 100644 index 00000000000..081da5659e8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_client.cpp @@ -0,0 +1,336 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef ANDROID +#include "../../implementation/configuration/include/internal_android.hpp" +#else +#include "../../implementation/configuration/include/internal.hpp" +#endif + +#include "offered_services_info_test_globals.hpp" +#include "someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +enum operation_mode_e { + SUBSCRIBE, + METHODCALL +}; + +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> all_offered_services; +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> local_offered_services; +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> remote_offered_services; + +class offered_services_info_test_client : public vsomeip_utilities::base_logger { +public: + offered_services_info_test_client(struct offer_test::service_info _service_info,offer_test::service_info _remote_service_info, operation_mode_e _mode) : + vsomeip_utilities::base_logger("OFIC", "OFFERED SERVICES INFO TEST CLIENT"), + service_info_(_service_info), + remote_service_info_(_remote_service_info), + operation_mode_(_mode), + app_(vsomeip::runtime::get()->create_application("offered_services_info_test_client")), + wait_until_registered_(true), + wait_until_service_available_(true), + wait_for_stop_(true), + last_received_response_(std::chrono::steady_clock::now()), + number_received_responses_(0), + stop_thread_(std::bind(&offered_services_info_test_client::wait_for_stop, this)), + test_offered_services_thread_(std::bind(&offered_services_info_test_client::test_offered_services, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + local_offered_services[service_info_.service_id].insert(service_info_.instance_id); + all_offered_services[service_info_.service_id].insert(service_info_.instance_id); + + local_offered_services[service_info_.service_id].insert((vsomeip::instance_t)(service_info_.instance_id + 1)); + all_offered_services[service_info_.service_id].insert((vsomeip::instance_t)(service_info_.instance_id + 1)); + + // offer remote service ID 0x2222 instance ID 0x2 (port configuration added to json file) + remote_offered_services[remote_service_info_.service_id].insert(remote_service_info_.instance_id); + all_offered_services[remote_service_info_.service_id].insert(remote_service_info_.instance_id); + + remote_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 1)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 1)); + all_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 1)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 1)); + + remote_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 2)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 2)); + all_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 2)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 2)); + + app_->register_state_handler( + std::bind(&offered_services_info_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&offered_services_info_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, + std::bind(&offered_services_info_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + // request all services + app_->request_service(service_info_.service_id, service_info_.instance_id); + app_->request_service(service_info_.service_id, vsomeip::instance_t(service_info_.instance_id + 1)); + app_->request_service(remote_service_info_.service_id, remote_service_info_.instance_id); + app_->request_service(vsomeip::service_t(remote_service_info_.service_id + 1), vsomeip::instance_t(remote_service_info_.instance_id + 1)); + app_->request_service(vsomeip::service_t(remote_service_info_.service_id + 2), vsomeip::instance_t(remote_service_info_.instance_id + 2)); + + app_->start(); + } + + ~offered_services_info_test_client() { + test_offered_services_thread_.join(); + stop_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << "."; + static int services_available =0; + std::lock_guard<std::mutex> its_lock(mutex_); + if(_is_available) { + services_available++; + if (services_available == 5) { + wait_until_service_available_ = false; + condition_.notify_one(); + } + } else { + wait_until_service_available_ = true; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if (_message->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + on_response(_message); + } + } + + void on_response(const std::shared_ptr<vsomeip::message> &_message) { + ++number_received_responses_; + static bool first(true); + if (first) { + first = false; + last_received_response_ = std::chrono::steady_clock::now(); + return; + } + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::steady_clock::now() - last_received_response_).count(), + (std::chrono::milliseconds(VSOMEIP_DEFAULT_WATCHDOG_TIMEOUT) + + std::chrono::milliseconds(1000)).count()); + last_received_response_ = std::chrono::steady_clock::now(); + std::cout << "."; + std::cout.flush(); + } + + void test_offered_services() { + if (operation_mode_ != operation_mode_e::METHODCALL) { + return; + } + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + while (wait_until_service_available_) { + condition_.wait(its_lock); + } + its_lock.unlock(); + its_lock.release(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + VSOMEIP_INFO << "TEST LOCAL SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_LOCAL, std::bind(&offered_services_info_test_client::on_offered_services_local, this, std::placeholders::_1)); + + // send shutdown command to service + if (std::future_status::timeout == all_callbacks_received_.get_future().wait_for(std::chrono::seconds(15))) { + ADD_FAILURE() << "Didn't receive all callbacks within time"; + } else { + std::shared_ptr<vsomeip::message> its_req = vsomeip::runtime::get()->create_request(); + its_req->set_service(service_info_.service_id); + its_req->set_instance(service_info_.instance_id); + its_req->set_method(service_info_.shutdown_method_id); + app_->send(its_req); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + VSOMEIP_INFO << "going down. Sent shutdown command to service"; + stop_condition_.notify_one(); + } + } + + void on_offered_services_local( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES LOCAL CALLBACK START" << std::endl; + EXPECT_EQ(2u, _services.size()); + bool local_service_test_failed(true); + for (auto its_pair : _services) { + local_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: "<< std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = local_offered_services.find(its_pair.first); + if (found_service != local_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + local_service_test_failed = false; + } + } + EXPECT_FALSE(local_service_test_failed); + } + std::cout << "ON OFFERED SERVICES LOCAL CALLBACK END" << std::endl; + VSOMEIP_INFO << "TEST REMOTE SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_REMOTE, std::bind(&offered_services_info_test_client::on_offered_services_remote, this, std::placeholders::_1)); + } + + void on_offered_services_remote( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES REMOTE CALLBACK START" << std::endl; + EXPECT_EQ(3u, _services.size()); + bool remote_service_test_failed(true); + for (auto its_pair : _services) { + remote_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: " << std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = remote_offered_services.find(its_pair.first); + if (found_service != remote_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + remote_service_test_failed = false; + } + } + EXPECT_FALSE(remote_service_test_failed); + } + std::cout << "ON OFFERED SERVICES REMOTE CALLBACK END" << std::endl; + VSOMEIP_INFO << "TEST ALL SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_ALL, std::bind(&offered_services_info_test_client::on_offered_services_all, this, std::placeholders::_1)); + } + + void on_offered_services_all( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES ALL CALLBACK START" << std::endl; + EXPECT_EQ(5u, _services.size()); + bool all_service_test_failed(true); + for (auto its_pair : _services) { + all_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: " << std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = all_offered_services.find(its_pair.first); + if (found_service != all_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + all_service_test_failed = false; + } + } + EXPECT_FALSE(all_service_test_failed); + } + std::cout << "ON OFFERED SERVICES ALL CALLBACK END" << std::endl; + all_callbacks_received_.set_value(); + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_INFO << "going down"; + app_->clear_all_handler(); + app_->stop(); + } + +private: + struct offer_test::service_info service_info_; + struct offer_test::service_info remote_service_info_; + operation_mode_e operation_mode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_service_available_; + std::mutex mutex_; + std::condition_variable condition_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + + std::chrono::steady_clock::time_point last_received_response_; + std::atomic<std::uint32_t> number_received_responses_; + std::promise<void> all_callbacks_received_; + std::thread stop_thread_; + std::thread test_offered_services_thread_; +}; + +static operation_mode_e passed_mode = operation_mode_e::METHODCALL; + +TEST(someip_offered_services_info_test, check_offered_services) +{ + offered_services_info_test_client its_sample(offer_test::service, offer_test::remote_service, passed_mode); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl; + return 1; + } + + if (std::string("SUBSCRIBE") == std::string(argv[1])) { + passed_mode = operation_mode_e::SUBSCRIBE; + } else if (std::string("METHODCALL") == std::string(argv[1])) { + passed_mode = operation_mode_e::METHODCALL; + } else { + std::cerr << "Wrong operation mode passed, exiting" << std::endl; + std::cerr << "Please specify a operation mode, like: " << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Valid operation modes are SUBSCRIBE and METHODCALL" << std::endl; + return 1; + } + +#if 0 + if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) { + use_same_service_id = true; + } else { + use_same_service_id = false; + } +#endif + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_globals.hpp new file mode 100644 index 00000000000..b74dfabbef3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_globals.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef OFFER_TEST_GLOBALS_HPP_ +#define OFFER_TEST_GLOBALS_HPP_ + +namespace offer_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; +}; + +uint8_t num_all_offered_services = 5; +uint8_t num_local_offered_services = 2; +uint8_t num_remote_offered_services = 3; + + +struct service_info service = { 0x1111, 0x1, 0x1111, 0x1111, 0x1000, 0x1404 }; +struct service_info remote_service = { 0x2222, 0x2, 0x2222, 0x2222, 0x2000, 0x2808 }; +} + +#endif /* OFFER_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_service.cpp new file mode 100644 index 00000000000..d1f9726d750 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/offered_services_info_tests/offered_services_info_test_service.cpp @@ -0,0 +1,267 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef ANDROID +#include "../../implementation/configuration/include/internal_android.hpp" +#else +#include "../../implementation/configuration/include/internal.hpp" +#endif // ANDROID + +#include "offered_services_info_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +static std::string service_number; +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> all_offered_services; +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> local_offered_services; +std::map<vsomeip::service_t, std::set<vsomeip::instance_t>> remote_offered_services; + + +class offer_test_service : public vsomeip_utilities::base_logger { +public: + offer_test_service(struct offer_test::service_info _service_info, struct offer_test::service_info _remote_service_info) : + vsomeip_utilities::base_logger("OTS1", "OFFER TEST SERVICE"), + service_info_(_service_info), + remote_service_info_(_remote_service_info), + // service with number 1 uses "routingmanagerd" as application name + // this way the same json file can be reused for all local tests + // including the ones with routingmanagerd + app_(vsomeip::runtime::get()->create_application( + (service_number == "1") ? "routingmanagerd" : + "offered_services_info_test_service" + service_number)), + wait_until_registered_(true), + shutdown_method_called_(false), + offer_thread_(std::bind(&offer_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&offer_test_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&offer_test_service::on_request, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&offer_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + app_->start(); + } + + ~offer_test_service() { + offer_thread_.join(); + } + + void offer() { + //offer local services + app_->offer_service(service_info_.service_id, service_info_.instance_id); + local_offered_services[service_info_.service_id].insert(service_info_.instance_id); + all_offered_services[service_info_.service_id].insert(service_info_.instance_id); + + app_->offer_service(service_info_.service_id, (vsomeip::instance_t)(service_info_.instance_id + 1)); + local_offered_services[service_info_.service_id].insert((vsomeip::instance_t)(service_info_.instance_id + 1)); + all_offered_services[service_info_.service_id].insert((vsomeip::instance_t)(service_info_.instance_id + 1)); + + // offer remote service ID 0x2222 instance ID 0x2 (port configuration added to json file) + app_->offer_service(remote_service_info_.service_id, remote_service_info_.instance_id); // reliable and unreliable port + remote_offered_services[remote_service_info_.service_id].insert(remote_service_info_.instance_id); + all_offered_services[remote_service_info_.service_id].insert(remote_service_info_.instance_id); + + + app_->offer_service((vsomeip::service_t)(remote_service_info_.service_id + 1), (vsomeip::instance_t)(remote_service_info_.instance_id + 1)); // only reliable port + remote_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 1)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 1)); + all_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 1)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 1)); + + + app_->offer_service((vsomeip::service_t)(remote_service_info_.service_id + 2), (vsomeip::instance_t)(remote_service_info_.instance_id + 2)); // only unreliable port + remote_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 2)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 2)); + all_offered_services[(vsomeip::service_t)(remote_service_info_.service_id + 2)].insert((vsomeip::instance_t)(remote_service_info_.instance_id + 2)); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + shutdown_method_called_ = true; + + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + app_->stop_offer_service(service_info_.service_id, (vsomeip::instance_t)(service_info_.instance_id + 1)); + + app_->stop_offer_service(remote_service_info_.service_id, remote_service_info_.instance_id); // reliable and unreliable port + app_->stop_offer_service((vsomeip::service_t)(remote_service_info_.service_id + 1), (vsomeip::instance_t)(remote_service_info_.instance_id + 1)); // only reliable port + app_->stop_offer_service((vsomeip::service_t)(remote_service_info_.service_id + 2), (vsomeip::instance_t)(remote_service_info_.instance_id + 2)); // only unreliable port + + app_->clear_all_handler(); + app_->stop(); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + VSOMEIP_INFO << "TEST LOCAL SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_LOCAL, std::bind(&offer_test_service::on_offered_services_local, this, std::placeholders::_1)); + + if (std::future_status::timeout == all_callbacks_received_.get_future().wait_for(std::chrono::seconds(15))) { + ADD_FAILURE() << "Didn't receive all callbacks within time"; + } + + while(!shutdown_method_called_) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + + void on_offered_services_local( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES LOCAL CALLBACK START" << std::endl; + EXPECT_EQ(2u, _services.size()); + bool local_service_test_failed(true); + uint16_t i=0; + for (auto its_pair : _services) { + local_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: "<< std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = local_offered_services.find(its_pair.first); + if (found_service != local_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + i++; + local_service_test_failed = false; + } + } + EXPECT_FALSE(local_service_test_failed); + } + EXPECT_EQ(offer_test::num_local_offered_services, i); + + std::cout << "ON OFFERED SERVICES LOCAL CALLBACK END" << std::endl; + + VSOMEIP_INFO << "TEST REMOTE SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_REMOTE, std::bind(&offer_test_service::on_offered_services_remote, this, std::placeholders::_1)); + } + + + void on_offered_services_remote( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES REMOTE CALLBACK START" << std::endl; + EXPECT_EQ(3u, _services.size()); + bool remote_service_test_failed(true); + uint16_t i=0; + for (auto its_pair : _services) { + remote_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: " << std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = remote_offered_services.find(its_pair.first); + if (found_service != remote_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + i++; + remote_service_test_failed = false; + } + } + EXPECT_FALSE(remote_service_test_failed); + } + EXPECT_EQ(offer_test::num_remote_offered_services, i); + + std::cout << "ON OFFERED SERVICES REMOTE CALLBACK END" << std::endl; + + VSOMEIP_INFO << "TEST ALL SERVICES"; + app_->get_offered_services_async(vsomeip::offer_type_e::OT_ALL, std::bind(&offer_test_service::on_offered_services_all, this, std::placeholders::_1)); + } + + + void on_offered_services_all( const std::vector<std::pair<vsomeip::service_t, vsomeip::instance_t>> &_services) { + std::cout << "ON OFFERED SERVICES ALL CALLBACK START" << std::endl; + EXPECT_EQ(5u, _services.size()); + bool all_service_test_failed(true); + uint16_t i=0; + for (auto its_pair : _services) { + all_service_test_failed = true; + std::cout << "CALLBACK VALUE -> Service: " << std::hex << std::get<0>(its_pair) << " instance: " << std::get<1>(its_pair) << std::endl; + auto found_service = all_offered_services.find(its_pair.first); + if (found_service != all_offered_services.end()) { + auto found_instance = found_service->second.find(its_pair.second); + if (found_instance != found_service->second.end()) { + i++; + all_service_test_failed = false; + } + } + EXPECT_FALSE(all_service_test_failed); + } + EXPECT_EQ(offer_test::num_all_offered_services, i); + std::cout << "ON OFFERED SERVICES ALL CALLBACK END" << std::endl; + all_callbacks_received_.set_value(); + } + +private: + struct offer_test::service_info service_info_; + struct offer_test::service_info remote_service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> shutdown_method_called_; + std::promise<void> all_callbacks_received_; + std::thread offer_thread_; +}; + +TEST(someip_offered_services_info_test, check_offered_services_as_rm_impl) +{ + offer_test_service its_sample(offer_test::service, offer_test::remote_service); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number, like: " << argv[0] << " 2" << std::endl; + return 1; + } + + service_number = std::string(argv[1]); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/CMakeLists.txt new file mode 100644 index 00000000000..e305ce6bced --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/CMakeLists.txt @@ -0,0 +1,81 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(payload_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + external_local_payload_test_client_external.json + external_local_payload_test_client_external_start.sh + external_local_payload_test_client_external_starter.sh + external_local_payload_test_client_local.json + external_local_payload_test_client_local_and_external_starter.sh + external_local_payload_test_client_local_start.sh + external_local_payload_test_client_local_starter.sh + external_local_payload_test_service.json + external_local_payload_test_service_client_external_start.sh + external_local_payload_test_service_start.sh + local_payload_test_client.json + local_payload_test_client_start.sh + local_payload_test_huge_payload_starter.sh + local_payload_test_service.json + local_payload_test_service_start.sh + local_payload_test_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(payload_test_service + payload_test_service.cpp +) + +# Add test executable. +add_executable(payload_test_client + payload_test_client.cpp + stopwatch.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + payload_test_service + payload_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME local_payload_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/local_payload_test_starter.sh +) + +# Add custom test command. +add_custom_test( + NAME local_payload_test_huge_payload + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/local_payload_test_huge_payload_starter.sh + TIMEOUT 1800 +) + +# Add custom test command. +add_custom_test( + NAME external_local_payload_test_client_local + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/external_local_payload_test_client_local_starter.sh +) + +# Add custom test command. +add_custom_test( + NAME external_local_payload_test_client_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/external_local_payload_test_client_external_starter.sh + TIMEOUT 480 +) + +# Add custom test command. +add_custom_test( + NAME external_local_payload_test_client_local_and_external + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/external_local_payload_test_client_local_and_external_starter.sh + TIMEOUT 480 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external.json.in new file mode 100644 index 00000000000..f6179cb9127 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external.json.in @@ -0,0 +1,53 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "external_local_payload_test_client_external", + "id" : "0x1343" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509", + "reliable" : + { + "port" : "30510", + "enable-magic-cookies" : "false" + } + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "external_local_payload_test_client_external", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_start.sh.in new file mode 100755 index 00000000000..5f6b7ea8359 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_start.sh.in @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_client_external +export VSOMEIP_CONFIGURATION=external_local_payload_test_client_external.json +./payload_test_client --udp --max-payload-size UDP +# We sleep to let the service restart with --tcp option so we can test +# communication via TCP. +sleep 5 +./payload_test_client --tcp --max-payload-size TCP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_starter.sh.in new file mode 100755 index 00000000000..b0d75abd856 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_external_starter.sh.in @@ -0,0 +1,121 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +# Parameter 2: number of TCP/UDP sockets the process should have open +check_tcp_udp_sockets_are_open () +{ + # Check that the passed pid/process does listen on at least one TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -lt $2 ] + then + ((FAIL+=1)) + fi +} + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the passed pid/process does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + ((FAIL+=1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + ((FAIL+=1)) + fi +} + +# Start the service for payload test with UDP +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service --udp & +SERIVCE_PID=$! + +# Display a message to show the user that he must now call the external client +# to finish the test successfully +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external local payload on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/payload_tests; ./external_local_payload_test_client_external_start.sh\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./external_local_payload_test_client_external_start.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** external_local_payload_test_client_external_start.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** external_local_payload_test_client_external.json and +** external_local_payload_test_service.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# The service should listen on a TCP and UDP socket now +sleep 1 +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + +# Wait until service is finished +# The client remotely shuts down the service if he has successfully transmitted +# all the packets with different payloads. Therefore we can assume that everything +# went well, even if we can only check the exit code of the service here. + +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $SERIVCE_PID || ((FAIL+=1)) + + +# Start the service for payload test with tcp +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service --tcp & +SERIVCE_PID=$! + +# The service should listen on a TCP and UDP socket now +sleep 1 +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + + +# Wait until service is finished +# The client remotely shuts down the service if he has successfully transmitted +# all the packets with different payloads. Therefore we can assume that everything +# went well, even if we can only check the exit code of the service here. + +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $SERIVCE_PID || ((FAIL+=1)) + +# Check if server exited sucessfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local.json.in new file mode 100644 index 00000000000..2666c106dcf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local.json.in @@ -0,0 +1,54 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "external_local_payload_test_client_local", + "id" : "0x1343" + } + ], + + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509", + "reliable" : + { + "port" : "30510", + "enable-magic-cookies" : "false" + } + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "external_local_payload_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_and_external_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_and_external_starter.sh.in new file mode 100755 index 00000000000..d8e9b94c8d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_and_external_starter.sh.in @@ -0,0 +1,139 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +# Parameter 2: number of TCP/UDP sockets the process should have open +check_tcp_udp_sockets_are_open () +{ + # Check that the passed pid/process does listen on at least one TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -lt $2 ] + then + ((FAIL+=1)) + fi +} + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the passed pid/process does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + ((FAIL+=1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + ((FAIL+=1)) + fi +} + +# Start the service +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service & +SERIVCE_PID=$! +sleep 1; + +# The service should listen on a TCP and UDP socket now +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + +# Start the client which sends messages over local UDS +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_client_local +export VSOMEIP_CONFIGURATION=external_local_payload_test_client_local.json +./payload_test_client --dont-shutdown-service & +CLIENT_PID=$! +sleep 1 + +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 +check_tcp_udp_sockets_are_closed $CLIENT_PID + +# Wait until client is finished +wait $CLIENT_PID || ((FAIL+=1)) + +# Display a message to show the user that he must now call the external client +# to finish the test successfully +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external local payload on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/payload_tests; ./external_local_payload_test_client_external_start.sh\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./external_local_payload_test_client_external_start.sh" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** external_local_payload_test_client_external_start.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** external_local_payload_test_client_external.json and +** external_local_payload_test_service.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# The service should still listen on a TCP and UDP socket +sleep 1 +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + +# Wait until service is finished +# The client remotely shuts down the service if he has successfully transmitted +# all the packets with different payloads. Therefore we can assume that everything +# went well, even if we can only check the exit code of the service here. + +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $SERIVCE_PID || ((FAIL+=1)) + + +# Start the service for payload test with tcp +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service --tcp & +SERIVCE_PID=$! + +# The service should listen on a TCP and UDP socket now +sleep 1 +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + + +# Wait until service is finished +# The client remotely shuts down the service if he has successfully transmitted +# all the packets with different payloads. Therefore we can assume that everything +# went well, even if we can only check the exit code of the service here. + +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $SERIVCE_PID || ((FAIL+=1)) + +# Check if client and server both exited sucessfully and the service didnt't +# have any open TCP/UDP sockets +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_start.sh.in new file mode 100755 index 00000000000..b79e534d24e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_client_local +export VSOMEIP_CONFIGURATION=external_local_payload_test_client_local.json +./payload_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_starter.sh.in new file mode 100755 index 00000000000..d28d1e4ef30 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_client_local_starter.sh.in @@ -0,0 +1,87 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +# Parameter 2: number of TCP/UDP sockets the process should have open +check_tcp_udp_sockets_are_open () +{ + # Check that the passed pid/process does listen on at least one TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -lt $2 ] + then + FAIL=$(($FAIL+1)) + fi +} + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the passed pid/process does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + FAIL=$(($FAIL+1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + FAIL=$(($FAIL+1)) + fi +} + +# Start the service +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service & +SERIVCE_PID=$! +sleep 1; + +# The service should listen on a TCP and UDP socket now +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 + +# Start the client +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_client_local +export VSOMEIP_CONFIGURATION=external_local_payload_test_client_local.json +./payload_test_client & +CLIENT_PID=$! + +# The service should still listen on a TCP and UDP socket now +check_tcp_udp_sockets_are_open $SERIVCE_PID 2 +# The client should use the shortcut over a local UDS instead of TCP/UDP, +# therefore he shouldn't have any open TCP/UDP sockets +check_tcp_udp_sockets_are_closed $CLIENT_PID + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# Wait until client and service are finished +for job in $(pgrep -P $$) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service.json.in new file mode 100644 index 00000000000..8c08c7faed4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service.json.in @@ -0,0 +1,51 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "external_local_payload_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "reliable" : + { + "port" : "30510", + "enable-magic-cookies" : "false" + } + } + ], + "npdu-default-timings" : { + "debounce-time-request" : "0", + "debounce-time-response" : "0", + "max-retention-time-request" : "0", + "max-retention-time-response" : "0" + }, + "routing" : "external_local_payload_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_client_external_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_client_external_start.sh.in new file mode 100755 index 00000000000..046d50bf6e4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_client_external_start.sh.in @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service --udp +# After payload was measured with UDP the client will restart and measure +# throughput with TCP +./payload_test_service --tcp \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_start.sh.in new file mode 100755 index 00000000000..90b1b38993a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/external_local_payload_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_payload_test_service +export VSOMEIP_CONFIGURATION=external_local_payload_test_service.json +./payload_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client.json.in new file mode 100644 index 00000000000..c72bb7864c7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client.json.in @@ -0,0 +1,36 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "local_payload_test_client", + "id" : "0x1343" + } + ], + "services" : + [ + ], + + "routing" : "local_payload_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client_start.sh.in new file mode 100755 index 00000000000..975be2af75d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_client_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=local_payload_test_client +export VSOMEIP_CONFIGURATION=local_payload_test_client.json +./payload_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_huge_payload_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_huge_payload_starter.sh.in new file mode 100755 index 00000000000..499a80fb853 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_huge_payload_starter.sh.in @@ -0,0 +1,35 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Start the service +export VSOMEIP_APPLICATION_NAME=local_payload_test_service +export VSOMEIP_CONFIGURATION=local_payload_test_service.json +./payload_test_service & +sleep 1; + +# Start the client +export VSOMEIP_APPLICATION_NAME=local_payload_test_client +export VSOMEIP_CONFIGURATION=local_payload_test_client.json +if ! ./payload_test_client --number-of-messages 100 --max-payload-size 10485760 +then + FAIL=$((FAIL+1)) +fi + +# Wait until service is finished +# Fail gets incremented if service exit +# with a non-zero exit code +wait $! || FAIL=$((FAIL+1)) + +# Check if client and server both exited sucessfully +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service.json.in new file mode 100644 index 00000000000..0454cfcabc4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service.json.in @@ -0,0 +1,40 @@ +{ + "unicast" : "127.0.0.1", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "local_payload_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + + "routing" : "local_payload_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service_start.sh.in new file mode 100755 index 00000000000..cc67f548802 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=local_payload_test_service +export VSOMEIP_CONFIGURATION=local_payload_test_service.json +./payload_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_starter.sh.in new file mode 100755 index 00000000000..3a9294c1a48 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/conf/local_payload_test_starter.sh.in @@ -0,0 +1,64 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the service does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + FAIL=$(($FAIL+1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + FAIL=$(($FAIL+1)) + fi +} + +# Start the service +export VSOMEIP_APPLICATION_NAME=local_payload_test_service +export VSOMEIP_CONFIGURATION=local_payload_test_service.json +./payload_test_service & +SERIVCE_PID=$! +sleep 1; + +check_tcp_udp_sockets_are_closed $SERIVCE_PID + +# Start the client +export VSOMEIP_APPLICATION_NAME=local_payload_test_client +export VSOMEIP_CONFIGURATION=local_payload_test_client.json +./payload_test_client & +CLIENT_PID=$! + +check_tcp_udp_sockets_are_closed $SERIVCE_PID +check_tcp_udp_sockets_are_closed $CLIENT_PID + +# Wait until client and service are finished +for job in $(pgrep -P $$) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || FAIL=$(($FAIL+1)) +done + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.cpp new file mode 100644 index 00000000000..ef5ba631f9c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.cpp @@ -0,0 +1,417 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "payload_test_client.hpp" + +enum class payloadsize + : std::uint8_t + { + UDS, TCP, UDP, USER_SPECIFIED +}; + +// this variables are changed via cmdline parameters +static bool use_tcp = false; +static bool call_service_sync = true; +static std::uint32_t sliding_window_size = vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_PAYLOAD_TESTS; +static payloadsize max_payload_size = payloadsize::UDS; +static bool shutdown_service_at_end = true; +static std::uint32_t user_defined_max_payload; +static std::uint32_t number_of_messages_to_send = 0; + +payload_test_client::payload_test_client( + bool _use_tcp, + bool _call_service_sync, + std::uint32_t _sliding_window_size) : + app_(vsomeip::runtime::get()->create_application()), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + call_service_sync_(_call_service_sync), + sliding_window_size_(_sliding_window_size), + blocked_(false), + is_available_(false), + number_of_messages_to_send_(number_of_messages_to_send ? number_of_messages_to_send : vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_PAYLOAD_TESTS), + number_of_sent_messages_(0), + number_of_sent_messages_total_(0), + number_of_acknowledged_messages_(0), + current_payload_size_(1), + all_msg_acknowledged_(false), + sender_(std::bind(&payload_test_client::run, this)) +{ +} + +bool payload_test_client::init() +{ + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&payload_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&payload_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&payload_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void payload_test_client::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void payload_test_client::stop() +{ + VSOMEIP_INFO << "Stopping..."; + // shutdown the service + if(shutdown_service_at_end) + { + shutdown_service(); + } + app_->clear_all_handler(); +} + +void payload_test_client::shutdown_service() +{ + request_->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request_->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request_->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request_); +} + +void payload_test_client::join_sender_thread() +{ + sender_.join(); +} + +void payload_test_client::on_state(vsomeip::state_type_e _state) +{ + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + } +} + +void payload_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) +{ + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) + { + if(is_available_ && !_is_available) + { + is_available_ = false; + } + else if(_is_available && !is_available_) + { + is_available_ = true; + send(); + } + } +} + +void payload_test_client::on_message(const std::shared_ptr<vsomeip::message>& _response) +{ + number_of_acknowledged_messages_++; + + ASSERT_EQ(_response->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID); + ASSERT_EQ(_response->get_instance(), vsomeip_test::TEST_SERVICE_INSTANCE_ID); + + if(call_service_sync_) + { + // We notify the sender thread every time a message was acknowledged + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + all_msg_acknowledged_ = true; + } + all_msg_acknowledged_cv_.notify_one(); + } + else + { + // We notify the sender thread only if all sent messages have been acknowledged + if(number_of_acknowledged_messages_ == number_of_messages_to_send_) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + number_of_acknowledged_messages_ = 0; + all_msg_acknowledged_ = true; + all_msg_acknowledged_cv_.notify_one(); + } + else if(number_of_acknowledged_messages_ % sliding_window_size_ == 0) + { + std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_); + all_msg_acknowledged_ = true; + all_msg_acknowledged_cv_.notify_one(); + } + } +} + +void payload_test_client::send() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); +} + +void payload_test_client::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + { + condition_.wait(its_lock); + } + + request_->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request_->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request_->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + // lock the mutex + std::unique_lock<std::mutex> lk(all_msg_acknowledged_mutex_); + + std::uint32_t max_allowed_payload = get_max_allowed_payload(); + + std::shared_ptr<vsomeip::payload> payload = vsomeip::runtime::get()->create_payload(); + std::vector<vsomeip::byte_t> payload_data; + bool reached_peak = false; + for(;;) + { + payload_data.assign(current_payload_size_ , vsomeip_test::PAYLOAD_TEST_DATA); + payload->set_data(payload_data); + request_->set_payload(payload); + + watch_.reset(); + watch_.start(); + + call_service_sync_ ? send_messages_sync(lk) : send_messages_async(lk); + + watch_.stop(); + print_throughput(); + + // Increase array size for next iteration + if(!reached_peak) { + current_payload_size_ *= 2; + } else { + current_payload_size_ /= 2; + } + + if(!reached_peak && current_payload_size_ > max_allowed_payload) + { + current_payload_size_ = max_allowed_payload; + reached_peak = true; + } else if(reached_peak && current_payload_size_ <= 1) { + break; + } + } + blocked_ = false; + + stop(); + std::thread t1([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));}); + t1.join(); + app_->stop(); + std::thread t([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));}); + t.join(); +} + + +std::uint32_t payload_test_client::get_max_allowed_payload() +{ + std::uint32_t payload; + switch (max_payload_size) + { + case payloadsize::UDS: + // TODO + payload = 1024 * 32 - 16; + break; + case payloadsize::TCP: + // TODO + payload = 4095 - 16; + break; + case payloadsize::UDP: + payload = VSOMEIP_MAX_UDP_MESSAGE_SIZE - 16; + break; + case payloadsize::USER_SPECIFIED: + payload = user_defined_max_payload; + break; + default: + payload = VSOMEIP_MAX_LOCAL_MESSAGE_SIZE; + break; + } + return payload; +} + +void payload_test_client::send_messages_sync(std::unique_lock<std::mutex>& lk) +{ + for (number_of_sent_messages_ = 0; + number_of_sent_messages_ < number_of_messages_to_send_; + number_of_sent_messages_++, number_of_sent_messages_total_++) + { + app_->send(request_); + // wait until the send messages has been acknowledged + // as long we wait lk is released; after wait returns lk is reacquired + all_msg_acknowledged_cv_.wait(lk, [&] + { return all_msg_acknowledged_;}); + // Reset condition variable (lk is locked again here) + all_msg_acknowledged_ = false; + } +} + +void payload_test_client::send_messages_async(std::unique_lock<std::mutex>& lk) +{ + for (number_of_sent_messages_ = 0; + number_of_sent_messages_ < number_of_messages_to_send_; + number_of_sent_messages_++, number_of_sent_messages_total_++) + { + app_->send(request_); + + if((number_of_sent_messages_+1) % sliding_window_size_ == 0) + { + // wait until all send messages have been acknowledged + // as long we wait lk is released; after wait returns lk is reacquired + all_msg_acknowledged_cv_.wait(lk, [&] + { return all_msg_acknowledged_;}); + + // Reset condition variable + all_msg_acknowledged_ = false; + } + } +} + +void payload_test_client::print_throughput() +{ + constexpr std::uint32_t usec_per_sec = 1000000; + stop_watch::usec_t time_needed = watch_.get_total_elapsed_microseconds(); + stop_watch::usec_t time_per_message = time_needed / number_of_sent_messages_; + std::double_t calls_per_sec = number_of_sent_messages_ + * (usec_per_sec / static_cast<double>(time_needed)); + std::double_t mbyte_per_sec = ((number_of_sent_messages_ + * current_payload_size_) + / (static_cast<double>(time_needed) / usec_per_sec)) / (1024*1024); + + VSOMEIP_INFO<< "[ Payload Test ] : :" + << "Payload size [byte]: " << std::dec << std::setw(8) << std::setfill('0') << current_payload_size_ + << " Messages sent: " << std::dec << std::setw(8) << std::setfill('0') << number_of_sent_messages_ + << " Meantime/message [usec]: " << std::dec << std::setw(8) << std::setfill('0') << time_per_message + << " Calls/sec: " << std::dec << std::setw(8) << std::setfill('0') << calls_per_sec + << " MiB/sec: " << std::dec << std::setw(8) << std::setfill('0') << mbyte_per_sec; +} + +TEST(someip_payload_test, send_different_payloads) +{ + payload_test_client test_client_(use_tcp, call_service_sync, sliding_window_size); + if (test_client_.init()) { + test_client_.start(); + test_client_.join_sender_thread(); + } +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + std::string tcp_enable("--tcp"); + std::string udp_enable("--udp"); + std::string sync_enable("--sync"); + std::string async_enable("--async"); + std::string sliding_window_size_param("--sliding-window-size"); + std::string max_payload_size_param("--max-payload-size"); + std::string shutdown_service_disable_param("--dont-shutdown-service"); + std::string numbers_of_messages("--number-of-messages"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(tcp_enable == argv[i]) + { + use_tcp = true; + } + else if(udp_enable == argv[i]) + { + use_tcp = false; + } + else if(sync_enable == argv[i]) + { + call_service_sync = true; + } + else if(async_enable == argv[i]) + { + call_service_sync = false; + } + else if(sliding_window_size_param == argv[i] && i + 1 < argc) + { + i++; + std::stringstream converter(argv[i]); + converter >> sliding_window_size; + } + else if(max_payload_size_param == argv[i] && i + 1 < argc) + { + i++; + if(std::string("UDS") == argv[i]) + { + max_payload_size = payloadsize::UDS; + } + else if(std::string("TCP") == argv[i]) + { + max_payload_size = payloadsize::TCP; + } + else if(std::string("UDP") == argv[i]) + { + max_payload_size = payloadsize::UDP; + } + else { + max_payload_size = payloadsize::USER_SPECIFIED; + std::stringstream converter(argv[i]); + converter >> user_defined_max_payload; + } + } + else if (numbers_of_messages == argv[i]) { + i++; + std::stringstream converter(argv[i]); + converter >> number_of_messages_to_send; + } + else if(shutdown_service_disable_param == argv[i]) + { + shutdown_service_at_end = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--tcp: Send messages via TCP\n" + << "--udp: Send messages via UDP (default)\n" + << "--sync: Wait for acknowledge before sending next message (default)\n" + << "--async: Send multiple messages w/o waiting for" + " acknowledge of service\n" + << "--sliding-window-size: Number of messages to send before waiting " + "for acknowledge of service. Default: " << sliding_window_size << "\n" + << "--max-payload-size: limit the maximum payloadsize of send requests. One of {" + "UDS (=" << VSOMEIP_MAX_LOCAL_MESSAGE_SIZE << "byte), " + "UDP (=" << VSOMEIP_MAX_UDP_MESSAGE_SIZE << "byte), " + "TCP (=" << VSOMEIP_MAX_TCP_MESSAGE_SIZE << "byte)}, default: UDS\n" + << "--dont-shutdown-service: Don't shutdown the service upon " + "finishing of the payload test\n" + << "--number-of-messages: Number of messages to send per payload size iteration\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.hpp new file mode 100644 index 00000000000..1bab6ba6ead --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_client.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PAYLOADTESTCLIENT_HPP_ +#define PAYLOADTESTCLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <cmath> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include "stopwatch.hpp" + +class payload_test_client +{ +public: + payload_test_client(bool _use_tcp, bool _call_service_sync, std::uint32_t _sliding_window_size); + bool init(); + void start(); + void stop(); + void join_sender_thread(); + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + void send(); + void run(); + +private: + void print_throughput(); + void send_messages_sync(std::unique_lock<std::mutex>& lk); + void send_messages_async(std::unique_lock<std::mutex>& lk); + void shutdown_service(); + std::uint32_t get_max_allowed_payload(); + +private: + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + bool call_service_sync_; + std::uint32_t sliding_window_size_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool is_available_; + const std::uint32_t number_of_messages_to_send_; + std::uint32_t number_of_sent_messages_; + std::uint32_t number_of_sent_messages_total_; + std::uint32_t number_of_acknowledged_messages_; + + std::uint32_t current_payload_size_; + + stop_watch watch_; + + bool all_msg_acknowledged_; + std::mutex all_msg_acknowledged_mutex_; + std::condition_variable all_msg_acknowledged_cv_; + + std::thread sender_; + +}; + +#endif /* PAYLOADTESTCLIENT_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.cpp new file mode 100644 index 00000000000..7d4c9243a9f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "payload_test_service.hpp" + +// this variables are changed via cmdline parameters + +static bool check_payload = true; + +payload_test_service::payload_test_service() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&payload_test_service::run, this)) +{ +} + +bool payload_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&payload_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&payload_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&payload_test_service::on_state, this, + std::placeholders::_1)); + return true; +} + +void payload_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void payload_test_service::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void payload_test_service::join_offer_thread() +{ + offer_thread_.join(); +} + +void payload_test_service::offer() +{ + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void payload_test_service::stop_offer() +{ + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void payload_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void payload_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + number_of_received_messages_++; + if(number_of_received_messages_ % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_PAYLOAD_TESTS == 0) + { + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "] payload size [byte]:" + << std::dec << _request->get_payload()->get_length(); + } + + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _request->get_method()); + + // Check the protocol version this shall be set to 0x01 according to the spec. + // TR_SOMEIP_00052 + ASSERT_EQ(0x01, _request->get_protocol_version()); + // Check the message type this shall be 0xx (REQUEST) according to the spec. + // TR_SOMEIP_00055 + ASSERT_EQ(vsomeip::message_type_e::MT_REQUEST, _request->get_message_type()); + + if (check_payload) { + std::shared_ptr<vsomeip::payload> pl = _request->get_payload(); + vsomeip::byte_t* pl_ptr = pl->get_data(); + for (vsomeip::length_t i = 0; i < pl->get_length(); i++) + { + ASSERT_EQ(vsomeip_test::PAYLOAD_TEST_DATA, *(pl_ptr+i)); + } + } + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); +} + +void payload_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) +{ + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + stop(); +} + +void payload_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); +} + +TEST(someip_payload_test, send_response_for_every_request) +{ + payload_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + std::string help("--help"); + std::string check("--do-not-check-payload"); + + int i = 1; + while (i < argc) + { + if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--help: print this help\n" + << "--do-not-check-payload: Don't verify payload data " + << "-> Use this flag for performance measurements!"; + } else if (check == argv[i]) { + check_payload = false; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.hpp new file mode 100644 index 00000000000..7d3c01d56ef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/payload_test_service.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PAYLOADTESTSERVICE_HPP_ +#define PAYLOADTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class payload_test_service +{ +public: + payload_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; +}; + +#endif /* PAYLOADTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.cpp new file mode 100644 index 00000000000..216780f5fa3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "stopwatch.hpp" + +#include <cassert> +#include <ctime> + + +#define USEC_PER_SEC 1000000ULL +#define NSEC_PER_USEC 1000ULL + + +stop_watch::usec_t stop_watch::get_total_elapsed_microseconds() const { + usec_t elapsed = total_elapsed_; + + if (started_) + elapsed += get_elapsed(); + + return elapsed; +} + +stop_watch::usec_t stop_watch::get_total_elapsed_seconds() const { + return get_total_elapsed_microseconds() / USEC_PER_SEC; +} + +stop_watch::usec_t stop_watch::now() { + struct timespec ts; + +#ifdef __QNX__ + const int ret = clock_gettime(CLOCK_MONOTONIC, &ts); +#else + const int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); +#endif + assert(!ret); + static_cast<void>(ret); // prevent warning in release build + + return (usec_t) ts.tv_sec * USEC_PER_SEC + (usec_t) ts.tv_nsec / NSEC_PER_USEC; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.hpp new file mode 100644 index 00000000000..5917e12b286 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/payload_tests/stopwatch.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef STOP_WATCH_H_ +#define STOP_WATCH_H_ + +#include <cstdint> + + +class stop_watch +{ +public: + typedef uint64_t usec_t; + + stop_watch() : + started_(false), + start_time_point_(0), + total_elapsed_(0) + { + } + + inline void reset() + { + started_ = false; + total_elapsed_ = 0; + } + + inline void start() + { + start_time_point_ = now(); + started_ = true; + } + + inline void stop() + { + total_elapsed_ += get_elapsed(); + started_ = false; + } + + usec_t get_total_elapsed_microseconds() const; + usec_t get_total_elapsed_seconds() const; + +private: + inline usec_t get_elapsed() const + { + return now() - start_time_point_; + } + + static usec_t now(); + + bool started_; + usec_t start_time_point_; + usec_t total_elapsed_; +}; + +#endif // STOP_WATCH_H_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/CMakeLists.txt new file mode 100644 index 00000000000..88317f1a269 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/CMakeLists.txt @@ -0,0 +1,115 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(pending_subscription_test LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + pending_subscription_test_master.json + pending_subscription_test_master_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(pending_subscription_test_service + pending_subscription_test_service.cpp +) + +# Add test executable. +set(service_discovery_sources + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/configuration_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/entry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/eventgroupentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ip_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv4_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv6_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/load_balancing_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_element_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/protection_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/selective_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/serviceentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/unknown_option_impl.cpp +) +set(message_sources + ${CMAKE_SOURCE_DIR}/implementation/message/src/deserializer.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/payload_impl.cpp +) +add_executable(pending_subscription_test_sd_msg_sender + pending_subscription_test_sd_msg_sender.cpp + ${service_discovery_sources} + ${message_sources} +) + +# Link vsomeip-sd to executable. +target_link_libraries(pending_subscription_test_sd_msg_sender ${VSOMEIP_NAME}-sd) + +# Add build dependencies and link libraries to executables. +set(executables + pending_subscription_test_service + pending_subscription_test_sd_msg_sender +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_subscribe + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_alternating_subscribe_unsubscribe + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE_UNSUBSCRIBE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_unsubscribe + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh UNSUBSCRIBE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_alternating_subscribe_unsubscribe_nack + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE_UNSUBSCRIBE_NACK + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_alternating_subscribe_unsubscribe_same_port + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE_UNSUBSCRIBE_SAME_PORT + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_subscribe_resubscribe_mixed + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE_RESUBSCRIBE_MIXED + TIMEOUT 300 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_subscribe_stopsubscribe_subscribe + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME pending_subscription_test_send_request_to_sd_port + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pending_subscription_test_master_starter.sh REQUEST_TO_SD + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master.json.in new file mode 100644 index 00000000000..b3453a0cbe9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master.json.in @@ -0,0 +1,55 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "pending_subscription_test_service", + "id" : "0xCAFE", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x1122", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x1111", + "is_reliable" : "false" + }, + { + "event" : "0x1112", + "is_reliable" : "false" + } + ] + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.23.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in new file mode 100755 index 00000000000..3aea9936ff9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/conf/pending_subscription_test_master_starter.sh.in @@ -0,0 +1,72 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +if [ $# -lt 1 ] +then + echo "Please pass a test mode to this script." + echo "For example: $0 SUSCRIBE" + echo "Valid subscription types include:" + echo " [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE_NACK, SUBSCRIBE_UNSUBSCRIBE_SAME_PORT, SUBSCRIBE_RESUBSCRIBE_MIXED, SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE, REQUEST_TO_SD]" + exit 1 +fi +TESTMODE=$1 +export VSOMEIP_CONFIGURATION=pending_subscription_test_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the services +./pending_subscription_test_service $1 & +PID_SERIVCE=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + echo "starting offer test on slave LXC offer_test_external_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/pending_subscription_tests; ./pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** pending_subscription_test_sd_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** pending_subscription_test_master.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +for job in $PID_SERIVCE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_globals.hpp new file mode 100644 index 00000000000..59ad88e66ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_globals.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_ +#define PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_ + +namespace pending_subscription_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::method_t notify_method_id; +}; + +struct service_info service = { 0x1122, 0x1, 0x1111, 0x1111, 0x1000, 0x1404, 0x4242 }; + +enum test_mode_e { + SUBSCRIBE, + SUBSCRIBE_UNSUBSCRIBE, + UNSUBSCRIBE, + SUBSCRIBE_UNSUBSCRIBE_NACK, + SUBSCRIBE_UNSUBSCRIBE_SAME_PORT, + SUBSCRIBE_RESUBSCRIBE_MIXED, + SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE, + REQUEST_TO_SD +}; + +} + +#endif /* PENDING_SUBSCRIPTION_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp new file mode 100644 index 00000000000..ce05f66c338 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_sd_msg_sender.cpp @@ -0,0 +1,1704 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iostream> +#include <memory> +#include <thread> +#include <chrono> +#include <cstring> +#include <future> + +#include <gtest/gtest.h> + +#include <boost/asio.hpp> + +#include <vsomeip/vsomeip.hpp> + +#include "../../implementation/utility/include/bithelper.hpp" +#include "../../implementation/message/include/deserializer.hpp" +#include "../../implementation/service_discovery/include/service_discovery.hpp" +#include "../../implementation/service_discovery/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/constants.hpp" +#include "../../implementation/service_discovery/include/enumeration_types.hpp" +#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp" +#include "../../implementation/message/include/message_impl.hpp" +#include "pending_subscription_test_globals.hpp" + +static char* remote_address; +static char* local_address; + +class pending_subscription : public ::testing::Test { +public: + pending_subscription() : + work_(std::make_shared<boost::asio::io_context::work>(io_)), + io_thread_(std::bind(&pending_subscription::io_run, this)) {} +protected: + + void TearDown() { + work_.reset(); + io_thread_.join(); + io_.stop(); + } + + void io_run() { + io_.run(); + } + + boost::asio::io_context io_; + std::shared_ptr<boost::asio::io_context::work> work_; + std::thread io_thread_; +}; + +/* + * @test Send 16 subscriptions to the service and check that every + * subscription is answered with an SubscribeEventgroupAck entry by the service. + * Check that the subscription is active at the end of the test and check that + * the notifications send by the service receive the client + */ +TEST_F(pending_subscription, send_multiple_subscriptions) +{ + std::promise<bool> trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + bool keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::uint32_t subscribe_acks_receiveid = 0; + std::uint32_t events_received = 0; + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + + std::uint32_t its_pos = 0; + + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(3u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + subscribe_acks_receiveid++; + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + events_received = 2; + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + } + } + } + if (subscribe_acks_receiveid == 30) { // all subscribeAcks received + trigger_notifications.set_value(true); + subscribe_acks_receiveid++; // don't set promise value again + } + if (its_received_events.size() == 2 && events_received == 2) { + // all events received as well + keep_receiving = false; + } + } + } + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + } + + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +/* + * @test Send 16 subscriptions to the service while alternating between Subscribe + * and Unsubscribe and check that every SubscribeEventgroupEntry (ttl > 0) + * is answered with an SubscribeEventgroupAck entry by the service. + * Check that the subscription is active at the end of the test and check that + * the notifications send by the service receive the client + */ +TEST_F(pending_subscription, send_alternating_subscribe_unsubscribe) +{ + std::promise<bool> trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(8); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic<std::uint32_t> notifications_received(0); + + bool triggered_notifications(false); + + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + bool keep_receiving(true); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + std::uint32_t its_pos = 0; + + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + } + } + if (acks_received == expected_acks && + responses_received == expected_responses && + notifications_received == expected_notifications) { + keep_receiving = false; + } + } + + + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + if (its_subscribe_message[11] % 2) { + its_subscribe_message[35] = 16; + its_subscribe_message[51] = 16; + } else { + its_subscribe_message[35] = 0; + its_subscribe_message[51] = 0; + } + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +/* + * @test Send 16 subscriptions to the service while only two contain a + * SubscribeEventgroupEntry and the rest contain StopSubscribeEventgroupEntries + * and check that all subscriptions with SubscribeEventgroupEntries are + * answered with an SubscribeEventgroupAck entry by the service. + * Check that the subscription is active at the end of the test and check that + * the notifications send by the service receive the client + */ +TEST_F(pending_subscription, send_multiple_unsubscriptions) +{ + std::promise<bool> trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(2); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic<std::uint32_t> notifications_received(0); + + bool triggered_notifications(false); + + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + bool keep_receiving(true); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + std::uint32_t its_pos = 0; + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + } + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + } + if (acks_received == expected_acks && + responses_received == expected_responses && + notifications_received == expected_notifications) { + std::cerr << "every thing received" << std::endl; + keep_receiving = false; + } + } + + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + if (its_subscribe_message[11] == 15 || its_subscribe_message[11] == 0x1) { + its_subscribe_message[35] = 16; + its_subscribe_message[51] = 16; + } else { + its_subscribe_message[35] = 0; + its_subscribe_message[51] = 0; + } + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +/* + * @test Send 16 subscriptions to the service and check that every second + * subscription is answered with an SubscribeEventgroupNack entry by the service. + * Check that the subscription is active at the end of the test and check that + * the notifications send by the service receive the client + */ +TEST_F(pending_subscription, send_alternating_subscribe_nack_unsubscribe) +{ + std::promise<bool> trigger_notifications; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(8); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_nacks(8); + std::atomic<std::uint32_t> nacks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic<std::uint32_t> notifications_received(0); + + bool triggered_notifications(false); + bool keep_receiving(true); + + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + acks_received = expected_acks; + responses_received = expected_responses; + nacks_received = expected_nacks; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + std::uint32_t its_pos = 0; + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + if (e->get_ttl()) { + EXPECT_EQ(16u, e->get_ttl()); + acks_received++; + } else { + EXPECT_EQ(0u, e->get_ttl()); + nacks_received++; + } + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + + if (!triggered_notifications && acks_received == expected_acks && + nacks_received == expected_nacks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + } + } + if (nacks_received == expected_nacks && + acks_received == expected_acks && + notifications_received == expected_notifications && + responses_received == expected_responses) { + keep_receiving = false; + } + } + + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_nacks, nacks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + if (its_subscribe_message[11] % 2) { + its_subscribe_message[35] = 16; + its_subscribe_message[51] = 16; + } else { + its_subscribe_message[35] = 0; + its_subscribe_message[51] = 0; + } + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +/* + * @test Send 16 subscriptions containing an UDP and TCP endpoint option + * to the service while alternating between Subscribe + * and Unsubscribe and check that every SubscribeEventgroupEntry (ttl > 0) + * is answered with an SubscribeEventgroupAck entry by the service. + * Check that the subscription is active at the end of the test and check that + * the notifications send by the service receive the client + */ +TEST_F(pending_subscription, send_alternating_subscribe_unsubscribe_same_port) +{ + std::promise<bool> trigger_notifications; + std::promise<void> tcp_connected; + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + boost::asio::ip::tcp::socket tcp_socket(io_, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 30490)); + tcp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + tcp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(8); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic<std::uint32_t> notifications_received(0); + + bool triggered_notifications(false); + + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + boost::system::error_code ec; + tcp_socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(remote_address), 40001), ec); + ASSERT_EQ(0, ec.value()); + tcp_connected.set_value(); + + bool keep_receiving(true); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + + std::uint32_t its_pos = 0; + + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_EQ(pending_subscription_test::service.event_id, its_received_events[0]); + EXPECT_EQ(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u), its_received_events[1]); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + } + } + if (acks_received == expected_acks && + responses_received == expected_responses && + notifications_received == expected_notifications) { + keep_receiving = false; + } + } + + + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + if (std::future_status::timeout == tcp_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't establish tcp connection within time"; + } + + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x4C, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x20, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x20, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x18, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a, + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x06, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + std::memcpy(&its_subscribe_message[76], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + if (its_subscribe_message[11] % 2) { + its_subscribe_message[35] = 16; + its_subscribe_message[51] = 16; + } else { + its_subscribe_message[35] = 0; + its_subscribe_message[51] = 0; + } + } + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.close(ec); + udp_socket.close(ec); +} + +/* + * @test Send a subscription as single message and afterwards send a + * resubscription containing a new subscription in the same message and check + * to receive initial event + */ +TEST_F(pending_subscription, subscribe_resubscribe_mixed) +{ + std::promise<void> first_initial_event_received; + std::promise<void> second_initial_event_received; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + std::vector<std::uint8_t> receive_buffer(4096); + std::set<vsomeip::event_t> its_received_events; + + const std::uint32_t expected_acks(3); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(2); + std::atomic<std::size_t> notifications_received(0); + + bool keep_receiving(true); + bool first_initial_event_checked(false); + bool second_initial_event_checked(false); + + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transfered = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + + std::uint32_t its_pos = 0; + + while (bytes_transfered > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transfered -= its_message_size; + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_GE(2u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(3u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + acks_received++; + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id || + its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id+1); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.insert(msg.get_method()); + if (its_received_events.size() == 2) { + EXPECT_TRUE(its_received_events.find(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u)) != its_received_events.end()); + EXPECT_TRUE(its_received_events.find(pending_subscription_test::service.event_id) != its_received_events.end()); + } + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received = its_received_events.size(); + } + } + + if (!first_initial_event_checked && notifications_received == 1) { + EXPECT_EQ(1u, its_received_events.size()); + EXPECT_TRUE(its_received_events.find(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u)) != its_received_events.end()); + // all subscribeAcks and one initial event of first event received + first_initial_event_received.set_value(); + first_initial_event_checked = true; + } + + if (!second_initial_event_checked && notifications_received == 2) { // events were received as well + // all subscribeAcks and one initial event of second event received + EXPECT_EQ(2u, its_received_events.size()); + EXPECT_TRUE(its_received_events.find(static_cast<vsomeip::event_t>(pending_subscription_test::service.event_id + 1u)) != its_received_events.end()); + EXPECT_TRUE(its_received_events.find(pending_subscription_test::service.event_id) != its_received_events.end()); + second_initial_event_received.set_value(); + second_initial_event_checked = true; + } + if (notifications_received == 2 && responses_received == 1) { + keep_receiving = false; + } + } + } + } + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_notifications, notifications_received); + EXPECT_EQ(expected_responses, responses_received); + }); + + std::thread send_thread([&]() { + try { + // call notify method to ensure to receive initial events + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x01, // eventgroup + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + + + + if (std::future_status::timeout == first_initial_event_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAck of first subscription within time"; + } + + // send second subscription with resubscription and new subscription + std::uint8_t its_subscribe_resubscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x00, 0x02, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + std::memcpy(&its_subscribe_resubscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + udp_socket.send_to(boost::asio::buffer(its_subscribe_resubscribe_message), target_sd); + + if (std::future_status::timeout == second_initial_event_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAck of second subscription within time"; + } + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +/* + * @test Send a SD message containing a Subscription followed by a StopSubscribe + * Subscribe entry to the same service. Check to receive an initial event + */ +TEST_F(pending_subscription, send_subscribe_stop_subscribe_subscribe) +{ + std::promise<bool> trigger_notifications; + std::promise<void> tcp_connected; + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + boost::asio::ip::tcp::socket tcp_socket(io_, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 30490)); + tcp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + tcp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + const std::uint32_t expected_acks(2); + std::atomic<std::uint32_t> acks_received(0); + + const std::uint32_t expected_responses(1); + std::atomic<std::uint32_t> responses_received(0); + + const std::uint32_t expected_notifications(1); + std::atomic<std::uint32_t> notifications_received(0); + + bool triggered_notifications(false); + + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + boost::system::error_code ec; + tcp_socket.connect(boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(remote_address), 40001), ec); + ASSERT_EQ(0, ec.value()); + tcp_connected.set_value(); + + bool keep_receiving(true); + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + acks_received = expected_acks; + responses_received = expected_responses; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + + std::uint32_t its_pos = 0; + + while (bytes_transferred > 0) { + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK, e->get_type()); + EXPECT_EQ(16u, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_TRUE(its_casted_entry->get_eventgroup() == pending_subscription_test::service.eventgroup_id); + } + } + EXPECT_EQ(0u, sd_msg.get_options().size()); + acks_received++; + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + its_received_events.push_back(msg.get_method()); + EXPECT_EQ(1u, its_received_events.size()); + EXPECT_EQ(1u, msg.get_payload()->get_length()); + EXPECT_EQ(0xDD, *msg.get_payload()->get_data()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(0x0, msg.get_client()); + notifications_received++; + } + } + + if (!triggered_notifications && acks_received == expected_acks) { // all subscribeAcks received + trigger_notifications.set_value(true); + triggered_notifications = true; + } + } + if (acks_received == expected_acks && + responses_received == expected_responses && + notifications_received == expected_notifications) { + keep_receiving = false; + } + } + } + EXPECT_EQ(expected_acks, acks_received); + EXPECT_EQ(expected_responses, responses_received); + EXPECT_EQ(expected_notifications, notifications_received); + }); + + std::thread send_thread([&]() { + if (std::future_status::timeout == tcp_connected.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't establish tcp connection within time"; + } + + try { + std::uint8_t its_normal_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x06, 0x00, 0x00, 0x10, // subscribe Eventgroup entry + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x50, // length + 0x00, 0x00, 0x00, 0x02, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, // length entries array + 0x06, 0x00, 0x00, 0x10, // subscribe Eventgroup entry + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x10, // 16 seconds TTL + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, // Stop subscribe Eventgroup entry + 0x11, 0x22, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, + 0x06, 0x00, 0x00, 0x10, // subscribe Eventgroup entry + 0x11, 0x22, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[80], &its_local_address.to_v4().to_bytes()[0], 4); + std::memcpy(&its_normal_subscribe_message[48], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + + udp_socket.send_to(boost::asio::buffer(its_normal_subscribe_message), target_sd); + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + + if (std::future_status::timeout == trigger_notifications.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all SubscribeAcks within time"; + } else { + // call notify method + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } catch (...) { + ASSERT_FALSE(true); + } + + }); + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + tcp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + tcp_socket.close(ec); + udp_socket.close(ec); +} + +/* + * @test Send a message with message type 0x0 (REQUEST) to the remote SD port + * and check if the remote SD continues to send offers + */ +TEST_F(pending_subscription, send_request_to_sd_port) +{ + std::promise<bool> all_offers_received; + + boost::asio::ip::udp::socket udp_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + udp_socket.set_option(boost::asio::ip::multicast::enable_loopback(false)); + udp_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.23.1").to_v4())); + udp_socket.set_option(boost::asio::socket_base::reuse_address(true)); + udp_socket.set_option(boost::asio::socket_base::linger(true, 0)); + + std::thread receive_thread([&](){ + bool keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + } else { + std::uint32_t its_pos = 0; + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be(&receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + its_pos += its_message_size; + bytes_transferred -= its_message_size; + + #if 0 + std::stringstream str; + for (size_t i = 0; i < bytes_transferred; i++) { + str << std::hex << std::setw(2) << std::setfill('0') << std::uint32_t(receive_buffer[i]) << " "; + } + std::cout << __func__ << " received: " << std::dec << bytes_transferred << " bytes: " << str.str() << std::endl; + #endif + static int offers_received = 0; + static int responses_received = 0; + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + EXPECT_EQ(2u, sd_msg.get_options().size()); + for (const auto& e : sd_msg.get_entries()) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(0xffffffu, e->get_ttl()); + EXPECT_EQ(pending_subscription_test::service.service_id, e->get_service()); + EXPECT_EQ(pending_subscription_test::service.instance_id, e->get_instance()); + offers_received++; + } + } else { // non-sd-message + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(pending_subscription_test::service.service_id, msg.get_service()); + EXPECT_EQ(pending_subscription_test::service.shutdown_method_id, msg.get_method()); + EXPECT_EQ(0x2222, msg.get_client()); + responses_received++; + } + } + + if (responses_received == 1) { // response to shutdown method was received as well + keep_receiving = false; + } else if (offers_received == 3 ) { // all multiple offers received + try { + all_offers_received.set_value(true); + } catch (const std::future_error& e) { + + } + } + } + } + } + }); + + std::thread send_thread([&]() { + try { + std::uint8_t its_subscribe_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x40, // length + 0x00, 0x00, 0x10, 0x01, + 0x01, 0x01, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, // message type is set to 0x0 (REQUEST) + 0x00, 0x00, 0x00, 0x20, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x00, // eventgroup + 0x06, 0x00, 0x00, 0x10, + 0x11, 0x22, 0x00, 0x01, // service / instance + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x10, 0x01, // eventgroup 2 + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // ip address + 0x00, 0x11, 0x77, 0x1a + }; + boost::asio::ip::address its_local_address = + boost::asio::ip::address::from_string(std::string(local_address)); + std::memcpy(&its_subscribe_message[64], &its_local_address.to_v4().to_bytes()[0], 4); + + boost::asio::ip::udp::socket::endpoint_type target_sd( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30490); + for (int var = 0; var < 15; ++var) { + udp_socket.send_to(boost::asio::buffer(its_subscribe_message), target_sd); + ++its_subscribe_message[11]; + } + + + if (std::future_status::timeout == all_offers_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive all Offers within time"; + } + + { + // call notify method (but don't expect notifications) to allow + // service to exit + std::uint8_t trigger_notifications_call[] = { + 0x11, 0x22, 0x42, 0x42, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(trigger_notifications_call), target_service); + } + + { + // call shutdown method + std::uint8_t shutdown_call[] = { + 0x11, 0x22, 0x14, 0x04, + 0x00, 0x00, 0x00, 0x08, + 0x22, 0x22, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service( + boost::asio::ip::address::from_string(std::string(remote_address)), + 30001); + udp_socket.send_to(boost::asio::buffer(shutdown_call), target_service); + } + + } catch (...) { + ASSERT_FALSE(true); + } + + }); + + send_thread.join(); + receive_thread.join(); + boost::system::error_code ec; + udp_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket.close(ec); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 4) { + std::cerr << "Please pass an target and local IP address and test mode to this binary like: " + << argv[0] << " 10.0.3.1 10.0.3.202 SUBSCRIBE" << std::endl; + std::cerr << "Testmodes are [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE]" << std::endl; + exit(1); + } + remote_address = argv[1]; + local_address = argv[2]; + std::string its_testmode = argv[3]; + if (its_testmode == std::string("SUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_multiple_subscriptions"; + } else if (its_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_alternating_subscribe_unsubscribe"; + } else if (its_testmode == std::string("UNSUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_multiple_unsubscriptions"; + } else if (its_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_NACK")) { + ::testing::GTEST_FLAG(filter) = "*send_alternating_subscribe_nack_unsubscribe"; + } else if (its_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_SAME_PORT")) { + ::testing::GTEST_FLAG(filter) = "*send_alternating_subscribe_unsubscribe_same_port"; + } else if (its_testmode == std::string("SUBSCRIBE_RESUBSCRIBE_MIXED")) { + ::testing::GTEST_FLAG(filter) = "*subscribe_resubscribe_mixed"; + } else if (its_testmode == std::string("SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE")) { + ::testing::GTEST_FLAG(filter) = "*send_subscribe_stop_subscribe_subscribe"; + } else if (its_testmode == std::string("REQUEST_TO_SD")) { + ::testing::GTEST_FLAG(filter) = "*send_request_to_sd_port"; + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_service.cpp new file mode 100644 index 00000000000..1a206b34b4a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/pending_subscription_tests/pending_subscription_test_service.cpp @@ -0,0 +1,392 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <future> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "pending_subscription_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class pending_subscription_test_service : public vsomeip_utilities::base_logger { +public: + pending_subscription_test_service(struct pending_subscription_test::service_info _service_info, pending_subscription_test::test_mode_e _testmode) : + vsomeip_utilities::base_logger("PSTS", "PENDING SUBSCRIPTION TEST SERVICE"), + service_info_(_service_info), + testmode_(_testmode), + app_(vsomeip::runtime::get()->create_application("pending_subscription_test_service")), + wait_until_registered_(true), + wait_until_shutdown_method_called_(true), + subscription_accepted_asynchronous_(false), + subscription_accepted_synchronous_(false), + offer_thread_(std::bind(&pending_subscription_test_service::run, this)) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&pending_subscription_test_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(_service_info.eventgroup_id); + app_->offer_event(service_info_.service_id, 0x1, + service_info_.event_id, + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + its_eventgroups.clear(); + its_eventgroups.insert(static_cast<vsomeip::eventgroup_t>(_service_info.eventgroup_id+1u)); + + app_->offer_event(service_info_.service_id, 0x1, + static_cast<vsomeip::event_t>(service_info_.event_id+1u), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&pending_subscription_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.notify_method_id, + std::bind(&pending_subscription_test_service::on_notify_method_called, this, + std::placeholders::_1)); + + app_->register_async_subscription_handler(service_info_.service_id, + 0x1, service_info_.eventgroup_id, + std::bind(&pending_subscription_test_service::subscription_handler_async, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5)); + app_->register_subscription_handler(service_info_.service_id, + 0x1, static_cast<vsomeip::eventgroup_t>(service_info_.eventgroup_id+1u), + std::bind(&pending_subscription_test_service::subscription_handler, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4)); + app_->start(); + } + + ~pending_subscription_test_service() { + offer_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, 0x1); + } + + void stop() { + app_->stop_offer_service(service_info_.service_id, 0x1); + app_->clear_all_handler(); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data( {0xDD}); + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + app_->notify(service_info_.service_id, service_info_.instance_id, + static_cast<vsomeip::event_t>(service_info_.event_id + 1u) , its_payload); + notify_method_called_.set_value(true); + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + if (testmode_ == pending_subscription_test::test_mode_e::REQUEST_TO_SD) { + // this testcase won't send valid subscriptions -> ensure to exit + subscription_accepted_asynchronous_ = true; + subscription_accepted_synchronous_ = true; + } + + while (!subscription_accepted_asynchronous_ || !subscription_accepted_synchronous_) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + switch (testmode_) { + case pending_subscription_test::test_mode_e::SUBSCRIBE: + async_subscription_handler_(true); + break; + case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE: + case pending_subscription_test::test_mode_e::UNSUBSCRIBE: + case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK: + case pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT: + case pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED: + case pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE: + case pending_subscription_test::test_mode_e::REQUEST_TO_SD: + default: + break; + } + + std::future<bool> itsFuture = notify_method_called_.get_future(); + if (std::future_status::timeout == itsFuture.wait_for(std::chrono::seconds(30))) { + ADD_FAILURE() << "notify method wasn't called within time!"; + } else { + EXPECT_TRUE(itsFuture.get()); + } + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + stop(); + } + + void subscription_handler_async(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, + bool _subscribed, const std::function<void(const bool)>& _cbk) { + (void)_uid; + (void)_gid; + VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed; + if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) { + async_subscription_handler_ = _cbk; + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_asynchronous_ = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cbk(true); + if (count_subscribe == 8 || count_unsubscribe == 7) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cbk(true); + if (count_subscribe == 2 || count_unsubscribe == 1) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (_subscribed) { + _cbk(((count_subscribe + 1) % 2)); // nack every second subscription + } else { + _cbk(true); + } + if (count_subscribe == 8 || count_unsubscribe == 7) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT) { + static int count_subscribe = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribe++ : count_unsubscribe++; + if (count_subscribe == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cbk(true); + if (count_subscribe == 8 || count_unsubscribe == 7) { + subscription_accepted_asynchronous_ = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED) { + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + _cbk(true); + subscription_accepted_asynchronous_ = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE) { + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_asynchronous_ = true; + // this test doesn't subscribe to the second eventgroup which is handled by the asynchronous + // subscription handler, set it to true here: + subscription_accepted_synchronous_ = true; + _cbk(true); + } + } + + bool subscription_handler(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) { + (void)_subscribed; + (void)_uid; + (void)_gid; + bool ret(false); + VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed. " << _subscribed; + if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE) { + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_synchronous_ = true; + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 8 && count_unsubscribe == 7) { + subscription_accepted_synchronous_ = true; + } + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::UNSUBSCRIBE) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 2 && count_unsubscribe == 1) { + subscription_accepted_synchronous_ = true; + } + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 8 && count_unsubscribe == 7) { + subscription_accepted_synchronous_ = true; + } + if (_subscribed) { + ret = ((count_subscribed + 1) % 2); // nack every second subscription + } else { + ret = true; + } + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT) { + static int count_subscribed = 0; + static int count_unsubscribe = 0; + _subscribed ? count_subscribed++ : count_unsubscribe++; + + if (count_subscribed == 1) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + if (count_subscribed == 8 && count_unsubscribe == 7) { + subscription_accepted_synchronous_ = true; + } + ret = true; + } else if (testmode_ == pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED) { + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + subscription_accepted_synchronous_ = true; + ret = true; + } + return ret; + } + +private: + struct pending_subscription_test::service_info service_info_; + pending_subscription_test::test_mode_e testmode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_shutdown_method_called_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> subscription_accepted_asynchronous_; + std::atomic<bool> subscription_accepted_synchronous_; + std::thread offer_thread_; + std::function<void(const bool)> async_subscription_handler_; + std::promise<bool> notify_method_called_; +}; + +pending_subscription_test::test_mode_e its_testmode(pending_subscription_test::test_mode_e::SUBSCRIBE); + +TEST(someip_pending_subscription_test, block_subscription_handler) +{ + pending_subscription_test_service its_sample(pending_subscription_test::service, its_testmode); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 2) { + std::cerr << "Please pass a test mode to this binary like: " + << argv[0] << " SUBSCRIBE" << std::endl; + std::cerr << "Testmodes are [SUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE, UNSUBSCRIBE, SUBSCRIBE_UNSUBSCRIBE_NACK, SUBSCRIBE_UNSUBSCRIBE_SAME_PORT]" << std::endl; + exit(1); + } + + std::string its_pased_testmode = argv[1]; + if (its_pased_testmode == std::string("SUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE; + } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE; + } else if (its_pased_testmode == std::string("UNSUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::UNSUBSCRIBE; + } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_NACK")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_NACK; + } else if (its_pased_testmode == std::string("SUBSCRIBE_UNSUBSCRIBE_SAME_PORT")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_UNSUBSCRIBE_SAME_PORT; + } else if (its_pased_testmode == std::string("SUBSCRIBE_RESUBSCRIBE_MIXED")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_RESUBSCRIBE_MIXED; + } else if (its_pased_testmode == std::string("SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE")) { + its_testmode = pending_subscription_test::test_mode_e::SUBSCRIBE_STOPSUBSCRIBE_SUBSCRIBE; + } else if (its_pased_testmode == std::string("REQUEST_TO_SD")) { + its_testmode = pending_subscription_test::test_mode_e::REQUEST_TO_SD; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/readme.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/readme.txt new file mode 100644 index 00000000000..2841795574a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/readme.txt @@ -0,0 +1,573 @@ +Configuration Test +------------------ +To start the configuration test from the build directory do: + +./configuration-test -someip ../config/vsomeip-test.json + +The expected output is: + +2015-02-10 08:47:31.503874 [info] Test "HOST ADDRESS" succeeded. +2015-02-10 08:47:31.507609 [info] Test "HAS CONSOLE" succeeded. +2015-02-10 08:47:31.507865 [info] Test "HAS FILE" succeeded. +2015-02-10 08:47:31.508001 [info] Test "HAS DLT" succeeded. +2015-02-10 08:47:31.508143 [info] Test "LOGFILE" succeeded. +2015-02-10 08:47:31.508315 [info] Test "LOGLEVEL" succeeded. +2015-02-10 08:47:31.508456 [info] Test "RELIABLE_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.508593 [info] Test "UNRELIABLE_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.508759 [info] Test "RELIABLE_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.508896 [info] Test "UNRELIABLE_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.509032 [info] Test "RELIABLE_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.509185 [info] Test "UNRELIABLE_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.509330 [info] Test "RELIABLE_TEST_4466_0321" succeeded. +2015-02-10 08:47:31.509467 [info] Test "UNRELIABLE_TEST_4466_0321" succeeded. +2015-02-10 08:47:31.509602 [info] Test "RELIABLE_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.509771 [info] Test "UNRELIABLE_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.509915 [info] Test "ADDRESS_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.510049 [info] Test "MIN_INITIAL_DELAY_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.510354 [info] Test "MAX_INITIAL_DELAY_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.510610 [info] Test "REPETITION_BASE_DELAY_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.513978 [info] Test "REPETITION_MAX_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.514177 [info] Test "CYCLIC_OFFER_DELAY_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.514280 [info] Test "CYCLIC_REQUEST_DELAY_TEST_1234_0022" succeeded. +2015-02-10 08:47:31.514397 [info] Test "MIN_INITIAL_DELAY_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.514618 [info] Test "MAX_INITIAL_DELAY_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.514754 [info] Test "REPETITION_BASE_DELAY_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.514901 [info] Test "REPETITION_MAX_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.515052 [info] Test "CYCLIC_OFFER_DELAY_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.515186 [info] Test "CYCLIC_REQUEST_DELAY_TEST_1234_0023" succeeded. +2015-02-10 08:47:31.515325 [info] Test "MIN_INITIAL_DELAY_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.515395 [info] Test "MAX_INITIAL_DELAY_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.515536 [info] Test "REPETITION_BASE_DELAY_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.515691 [info] Test "REPETITION_MAX_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.515834 [info] Test "CYCLIC_OFFER_DELAY_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.515971 [info] Test "CYCLIC_REQUEST_DELAY_TEST_2277_0022" succeeded. +2015-02-10 08:47:31.516109 [info] Test "MIN_INITIAL_DELAY_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516279 [info] Test "MAX_INITIAL_DELAY_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516380 [info] Test "REPETITION_BASE_DELAY_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516512 [info] Test "REPETITION_MAX_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516610 [info] Test "CYCLIC_OFFER_DELAY_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516736 [info] Test "CYCLIC_REQUEST_DELAY_TEST_2266_0022" succeeded. +2015-02-10 08:47:31.516874 [info] Test "ADDRESS_TEST_4466_0321" succeeded. +2015-02-10 08:47:31.516974 [info] Test "SERVICE DISCOVERY PROTOCOL" succeeded. +2015-02-10 08:47:31.517106 [info] Test "SERVICE DISCOVERY PORT" succeeded. + + +Application test +---------------- + +This test tests starting and stopping a vsomeip application in various ways. + +Automatic start from build directory: + +ctest -V -R application_test + +Manual start from sub folder test of build directory: + +./application_test_starter.sh + + +Magic Cookies Test +------------------ +To run the magic cookies test you need two devices on the same network. The network addresses within +the configuration files need to be adapted to match the devices addresses. + +To start the magic-cookies-test from the build-directory do: + +Automatic start from build directory: + +ctest -V -R magic_cookies_test + +Manual start from sub folder test of build directory: + +# On external host run +./magic_cookies_test_service_start.sh + +# On local host run +./magic_cookies_test_client_start.sh + + +The expected result is an output like this on service side: + +2015-02-10 08:42:07.317695 [info] Received a message with Client/Session [1343/0001] +2015-02-10 08:42:07.360105 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.360298 [info] Received a message with Client/Session [1343/0003] +2015-02-10 08:42:07.360527 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.360621 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.360714 [info] Received a message with Client/Session [1343/0006] +2015-02-10 08:42:07.360850 [info] Received a message with Client/Session [1343/0007] +2015-02-10 08:42:07.361021 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.361107 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.361191 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.361276 [info] Received a message with Client/Session [1343/000b] +2015-02-10 08:42:07.361434 [info] Received a message with Client/Session [1343/000c] +2015-02-10 08:42:07.361558 [info] Received a message with Client/Session [1343/000d] +2015-02-10 08:42:07.361672 [error] Detected Magic Cookie within message data. Resyncing. +2015-02-10 08:42:07.361761 [info] Received a message with Client/Session [1343/000f] + +Header Factory Tests +-------------------- + +The following things are tested: +a) create request + --> check "Protocol Version" / "Message Type" / "Return Type" fields +b) create request, fill header, create response + --> compare header fields of request & response +c) create notification + --> check "Protocol Version" / "Message Type" / "Return Type" fields +d) create message, fill header (service/instance/method/interface version/message type) + --> send message 10 times + --> receive message and check client id / session id + +a) to c) are combined in one binary. d) is composed out of a client and service. + +To start the header factory tests from the build directory do: + +Automatic start from build directory: +ctest -V -R header_factory_test + +Manual start from build directory: +cd test +./header_factory_test +# Start client and service separately +./header_factory_test_service_start.sh & +./header_factory_test_client_start.sh +# Alternatively start client and service with one script +./header_factory_test_send_receive_starter.sh + +All tests should be marked as "passed". + +Routing Tests +------------- + +The following things are tested: +a) create a service instance + - check that it is accessible from a local client but invisible for an external client +b) create a service instance, configure it to be externally visible + - check that it is accessible from a local client and from a external client + +a) and b) are composed out of a service each and one common client binary which is used +with different configuration files. + +Automatic start from build directory: + +ctest -V -R local_routing_test + +A message will be shown when the external client should be started. + +Manual start from build directory: +cd test +# First part with local client +# Start client and service with one script +./local_routing_test_starter.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +# Start the service +./local_routing_test_service_start.sh & +# Start the client +./local_routing_test_client_start.sh + +# Second part with external client +# Start client and service with one script +./external_local_routing_test_starter.sh +# Start the external client from an external host when the message is displayed to start it +./external_local_routing_test_client_external_start.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +# Start the service +./external_local_routing_test_service_start.sh & +# Start the client +./local_routing_test_client_start.sh +# Start the external client from an external host after local client has finished +./external_local_routing_test_client_external_start.sh + + +All tests should be marked as "passed". + +Payload Tests +------------- + +The following things are tested: +a) create a local service + - send messages with payloads of different size from a local client to the service + - check that the messages are received correctly + - measure the throughput +b) create a service instance, configure it to be externally visible + - send messages with payloads of different size from a local client to the service + - check that the messages are received correctly + - measure the throughput +c) create a service instance, configure it to be externally visible + - send messages with payloads of different size from an external client to the service + - check that the messages are received correctly + - measure the throughput +d) create a service instance, configure it to be externally visible + - send messages with payloads of different size from a local client to the service + - send messages with payloads of different size from an external client to the service + - check that the messages are received correctly + - measure the throughput + +The tests a) to d) are composed out of a service and a client binary which are called +with different configuration files and parameters. + +Automatic start from build directory: + +ctest -V -R payload_test + +A message will be shown when the external clients should be started. + +Manual start from build directory: +cd test + +# First part with local client +# start client and service with one script +./local_payload_test_starter.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +./local_payload_test_service_start.sh & +./local_payload_test_client_start.sh + +# Second part with external visible service and local client +# start client and service with one script +./external_local_payload_test_client_local_starter.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +./external_local_payload_test_service_start.sh & +./external_local_payload_test_client_local_start.sh + +# Third part with external visible service and external client +# start client and service with one script +./external_local_payload_test_client_external_starter.sh +# Start the external client from an external host if asked to +./external_local_payload_test_client_external_start.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +./external_local_payload_test_service_client_external_start.sh +# Start the external client from an external host +./external_local_payload_test_client_external_start.sh + +# Fourth part with external visible service and local and external client +# start client and service with one script +./external_local_payload_test_client_local_and_external_starter.sh +# Start the external client from an external host if asked to +./external_local_payload_test_client_external_start.sh + +# Alternatively start client and service separately +# Warning some checks are done within the *_starter.sh script. +# This should only be used for debugging +./external_local_payload_test_service_client_external_start.sh & +# Start the local client +VSOMEIP_APPLICATION_NAME=external_local_payload_test_client_local \ +VSOMEIP_CONFIGURATION=external_local_payload_test_client_local.json \ +./payload_test_client --dont-shutdown-service +# Start the external client after the local client is finished from an +# external host +./external_local_payload_test_client_external_start.sh + +All tests should be marked as "passed". + + +Big payload tests +----------------- + +This test tests the possibility to sent messages with bigger payloads +for local and TCP communication. + +The test will send a messages with 600k payload from a client to a service. +The service will reply with a response containing 600k payload as well. +This is repeated 10 times. +There is a version for local and for TCP communication available. +Additionally there are test versions available which sent up to 10MiB big +messages and a version which tests the limitiation of message sizes configurable +via json file. + +Automatic start from the build directory: + +ctest -V -R big_payload_test_local + +Manual start from sub folder test of build directory: + +./big_payload_test_service_local_start.sh & +./big_payload_test_client_local_start.sh + + +Automatic start of the TCP version from the build directory: + +ctest -V -R big_payload_test_external + +Manual start from sub folder test of build directory: + +./big_payload_test_client_start.sh + +# On external host run +./big_payload_test_service_external_start.sh + + +Client ID tests +--------------- + +This tests tests communication over two nodes with multiple services on both +nodes. + +The test setup is as followed: +* There are six services with one method each. +* Three of the services run on node 1. +* Three of the services run on node 2. +* Each of the services sends ten requests to the other services and waits + until it received a response for every request. +* If all responses have been received, the service shutdown. + +Automatic start from the build directory: + +ctest -V -R client_id_test_diff_client_ids_diff_ports + +Manual start from sub folder test of build directory: + +./client_id_test_master_starter.sh client_id_test_diff_client_ids_diff_ports_master.json + +Second version where all services on one node use the same port: + +Automatic start from the build directory: + +ctest -V -R client_id_test_diff_client_ids_same_ports + +Manual start from sub folder test of build directory: + +./client_id_test_master_starter.sh client_id_test_diff_client_ids_same_ports_master.json + + +Subscribe notify tests +---------------------- +This tests tests subscribe notify mechanism over two nodes with multiple services +on both nodes. + +The test setup is as followed: +* There are six services offering one event each. +* Three of the services run on node 1. +* Three of the services run on node 2. +* Each of the services waits until all other services are available. +* Each of the services subscribes to the offered event of all the other services. +* Each of the services then waits until the other services have subscribed to + its event. +* Each of the services then starts to sent out ten notifications for its event. +* Each service waits until it received the correct amount of notifications from + all other services. +* If all notifications have been received, the service shuts down. + +Automatic start from the build directory (example): + +ctest -V -R subscribe_notify_test_diff_client_ids_diff_ports_udp + +Manual start from sub folder test of build directory: + +./subscribe_notify_test_master_starter.sh UDP subscribe_notify_test_diff_client_ids_diff_ports_master.json + +There are multiple versions of this test which differ in the used subscription +method and port setup (use ctest -N to see all). For manual start the desired +description method has to be passed to the starter script as first parameter. + +The subscribe_notify_test_one_event_two_eventgroups_* tests are testing the +requirement that for events which are member of multiple eventgroups initial +events shall be sent per eventgroup. However normal updates of the event should +be sent only once even if a remote subscriber is subscribed to multiple of the +event's eventgroups (TR_SOMEIP_00570). + + +CPU load test +------------- +This test does a increasing number of synchronous function calls to the same +method of the service and measures CPU load for each batch of function calls. +All method calls transport a payload of 40 Bytes. The responses don't transport +any payload. + +The CPU load is measured thorugh the proc fs. +If the test prints a message like: + + Synchronously sent 0890 messages. CPU load [%]: 12.68 + +This means that the test process consumed 12% of the jiffies consumed by +complete system while doing 890 methodcalls. + +Automatic start from the build directory (example): + +ctest -V -R cpu_load_test + + +Initial event tests +---------------------- +This tests tests initial event mechanism over two nodes with multiple services +on both nodes. + +The test setup is as followed: +* There are six services offering one event each. +* Three of the services run on node 1. +* Three of the services run on node 2. +* All of the services initially set their event to their service id and notify + once +* On each node there are 20 client applications which subscribe to all of the + services events which are started at different times +* Each client waits until it received one notification (the initial one) from + all services and then exits. +* If all clients exited, the services are killed as well + +Automatic start from the build directory (example): + +ctest -V -R initial_event_test_diff_client_ids_diff_ports_udp + +Manual start from sub folder test of build directory: +./initial_event_test_master_starter.sh UDP initial_event_test_diff_client_ids_diff_ports_master.json + +There are multiple versions of this test which differ in the used subscription +method and port setup (use ctest -N to see all). For manual start the desired +description method has to be passed to the starter script as first parameter. + +Offer tests +----------- +This tests test various cases of offering a service and error recovery +after an application became unresponsive + +* Rejecting offer of service instance whose hosting application is + still alive. +* Rejecting offer of service instance whose hosting application is + still alive with daemon +* Accepting offer of service instance whose hosting application + crashed with (send SIGKILL) +* Accepting offer of service instance whose hosting application became + unresponsive (SIGSTOP) +* Rejecting offers for which there is already a pending offer +* Rejecting remote offer for which there is already a local offer +* Rejecting a local offer for which there is already a remote offer + +Automatic start from the build directory (example): + +ctest -V -R offer_tests + +Manual start from sub folder test of build directory: +./offer_test_local_starter +./offer_test_external_master_starter.sh + +Tests in detail: +Rejecting offer of service instance whose hosting application is still +alive: +* start application which offers service +* start client which continuously exchanges messages with the service +* start application which offers the same service again -> should be + rejected and an error message should be printed. +* Message exchange with client application should not be interrupted. + +Rejecting offer of service instance whose hosting application is still +alive with daemon +* start daemon (needed as he has to ping the offering client) +* start application which offers service +* start client which continuously exchanges messages with the service +* start application which offers the same service again -> should be + rejected and an error message should be printed. +* Message exchange with client application should not be interrupted. + +Accepting offer of service instance whose hosting application crashed +with (send SIGKILL) +* start daemon +* start application which offers service +* start client which exchanges messages with the service +* kill application with SIGKILL +* start application which offers the same service again -> should be + accepted. +* start another client which exchanges messages with the service +* Client should now communicate with new offerer. + +Accepting offer of service instance whose hosting application became +unresponsive (SIGSTOP) +* start daemon +* start application which offers service +* Send a SIGSTOP to the service to make it unresponsive +* start application which offers the same service again -> should be + marked as PENDING_OFFER and a ping should be sent to the paused + application. +* After the timeout passed the new offer should be accepted. +* start client which exchanges messages with the service +* Client should now communicate with new offerer. + +Rejecting offers for which there is already a pending offer +* start daemon +* start application which offers service +* Send a SIGSTOP to the service to make it unresponsive +* start application which offers the same service again -> should be + marked as PENDING_OFFER and a ping should be sent to the paused + application. +* start application which offers the same service again -> should be + rejected as there is already a PENDING_OFFER pending. +* After the timeout passed the new offer should be accepted. +* start client which exchanges messages with the service +* Client should now communicate with new offerer. + +Rejecting a local offer for which there is already a remote offer: +* start daemon +* start application which offers service +* start daemon remotely +* start same application which offers the same service again remotely + -> should be rejected as there is already a service instance + running in the network + +Rejecting remote offer for which there is already a local offer +* start application which offers service +* send SD message trying to offer the same service instance as already + offered locally from a remote host -> should be rejected + +nPDU tests +----------------- + +This test is intended to test the functionality of the so called nPDU +feature. The test setup is as followed: + +* There are two nodes, one hosting the services, one hosting the clients. +* On each of the nodes is a routing manager daemon (RMD) started whose only + purpose is to provide routing manager functionality and shutdown the clients + and services at the end. +* There are four services created. Each of the services has four methods. +* All services are listening on the same port. Therefore there only is: + * one server endpoint created in the RMD on service side + * one client endpoint created in the RMD on client side +* There are four clients created. Each of the clients will: + * Create a thread for each service + * Create a thread for each method of each service + * Send multiple messages with increasing payload to each of the services' + methods from the corresponding thread. + * After sending the threads will sleep the correct amount of time to insure + applicative debounce > debounce time + max retention time. +* After all messages have been sent to the services the clients will notify the + RMD that they're finished. The RMD then instructs the RMD on service side to + shutdown the services and exit afterwards. After that the RMD on client side + exits as well. +* Upon receiving a method call the service will check if the debounce time + specified in the json file for this method was undershot and print out a + warning. +* The test first runs in synchronous mode and waits for a response of the + service before sending the next message. +* After that the test runs in a mode where no response from the service are + required (message type REQUEST_NO_RETURN) thus the clients send at maximum + allowed frequency. + +Automatic start from build directory: + +ctest -V -R npdu_test_UDP +ctest -V -R npdu_test_TCP + +A message will be shown when the external clients should be started. + +Manual start: +# Service side +./npdu_test_service_npdu_start.sh + +# Client side UDP mode +./npdu_test_client_npdu_start.sh UDP + +# Client side TCP mode +./npdu_test_client_npdu_start.sh TCP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/CMakeLists.txt new file mode 100644 index 00000000000..822246f14c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(regression_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + climate_test_master.json + climate_test_master_starter.sh + climate_test_slave.json + climate_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(climate_test_service + climate_test_service.cpp +) + +# Add test executable. +add_executable(climate_test_client + climate_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + climate_test_service + climate_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME climate_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/climate_test_master_starter.sh + TIMEOUT 25 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_client.cpp new file mode 100644 index 00000000000..6674907aa6a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_client.cpp @@ -0,0 +1,192 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include <gtest/gtest.h> + +#include "climate_test_globals.hpp" + +class client_sample { +public: + client_sample(struct climate_test::service_info _service_info) : + app_(vsomeip::runtime::get()->create_application()), + service_info_(_service_info) { + } + + bool init() { + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + app_->register_state_handler( + std::bind(&client_sample::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + vsomeip::ANY_SERVICE, service_info_.instance_id, vsomeip::ANY_METHOD, + std::bind(&client_sample::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(service_info_.service_id, service_info_.instance_id, + std::bind(&client_sample::on_availability, + this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + std::set<vsomeip::eventgroup_t> its_groups; + its_groups.insert(service_info_.eventgroup_id); + app_->request_event( + service_info_.service_id, + service_info_.instance_id, + service_info_.event_id, + its_groups, + vsomeip::event_type_e::ET_FIELD); + app_->subscribe(service_info_.service_id, service_info_.instance_id, service_info_.eventgroup_id); + + return true; + } + + void start() { + app_->start(); + } + + void stop() { + app_->clear_all_handler(); + app_->unsubscribe(service_info_.service_id, service_info_.instance_id, service_info_.eventgroup_id); + app_->release_event(service_info_.service_id, service_info_.instance_id, service_info_.event_id); + app_->release_service(service_info_.service_id, service_info_.instance_id); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(service_info_.service_id, service_info_.instance_id); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + VSOMEIP_INFO << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + + availability_handler_calls++; + } + + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + std::stringstream its_message; + its_message << "Received a notification for Event [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_method() << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_session() + << "] = "; + std::shared_ptr<vsomeip::payload> its_payload = + _response->get_payload(); + EXPECT_EQ(its_payload->get_length(), 5); + its_message << "(" << std::dec << its_payload->get_length() << ") "; + for (uint32_t i = 0; i < its_payload->get_length(); ++i) { + its_message << std::hex << std::setw(2) << std::setfill('0') + << (int) its_payload->get_data()[i] << " "; + } + + if ((its_payload->get_length() % 5) == 0) { + notifications_received++; + if (notifications_received == 2) { + // Send message to trigger second part of the test + std::shared_ptr<vsomeip::message> its_set + = vsomeip::runtime::get()->create_message(); + its_set->set_message_type(vsomeip_v3::message_type_e::MT_REQUEST_NO_RETURN); + its_set->set_service(service_info_.service_id); + its_set->set_instance(service_info_.instance_id); + its_set->set_method(service_info_.get_method_id); + + const vsomeip::byte_t its_data[]{0x07}; + std::shared_ptr<vsomeip::payload> its_set_payload + = vsomeip::runtime::get()->create_payload(); + its_set_payload->set_data(its_data, sizeof(its_data)); + its_set->set_payload(its_set_payload); + app_->send(its_set); + std::this_thread::sleep_for(climate_test::MSG_SEND_WAIT_INTERVAL); + } + + if (notifications_received < 3) { + request_release(); + } else if (notifications_received == 4) { + // All expected notifications received, stop the client and send shutdown message to service + EXPECT_EQ(availability_handler_calls, 9); + + std::shared_ptr<vsomeip::message> its_set + = vsomeip::runtime::get()->create_message(); + its_set->set_message_type(vsomeip_v3::message_type_e::MT_REQUEST_NO_RETURN); + its_set->set_service(service_info_.service_id); + its_set->set_instance(service_info_.instance_id); + its_set->set_method(service_info_.shutdown_method_id); + app_->send(its_set); + std::this_thread::sleep_for(climate_test::MSG_SEND_WAIT_INTERVAL); + stop(); + } + } + } + + void request_release() { + app_->release_event(service_info_.service_id, service_info_.instance_id, service_info_.event_id); + app_->release_service(service_info_.service_id, service_info_.instance_id); + std::this_thread::sleep_for(climate_test::OFFER_CYCLE_INTERVAL); + app_->request_service(service_info_.service_id, service_info_.instance_id); + std::set<vsomeip::eventgroup_t> its_groups; + its_groups.insert(service_info_.eventgroup_id); + app_->request_event( + service_info_.service_id, + service_info_.instance_id, + service_info_.event_id, + its_groups, + vsomeip::event_type_e::ET_FIELD); + app_->subscribe(service_info_.service_id, service_info_.instance_id, service_info_.eventgroup_id); + } + +private: + std::shared_ptr< vsomeip::application > app_; + struct climate_test::service_info service_info_; + uint8_t availability_handler_calls = 0; + uint8_t notifications_received = 0; +}; + +TEST(someip_subscribe_notify_test_example, stop_without_unregister) +{ + client_sample its_sample(climate_test::service); + + if (its_sample.init()) { + its_sample.start(); + } +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_globals.hpp new file mode 100644 index 00000000000..37a754d60f8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_globals.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP +#define VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP + +namespace climate_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t get_method_id; + vsomeip::method_t shutdown_method_id; +}; + +struct service_info service = { 0x1234, 0x5678, 0x0421, 0x8778, 0x4465, 0x0001, 0x0002}; + +constexpr std::chrono::seconds OFFER_CYCLE_INTERVAL = std::chrono::seconds(1); +constexpr std::chrono::milliseconds MSG_SEND_WAIT_INTERVAL = std::chrono::milliseconds(500); +} + +#endif // VSOMEIP_EXAMPLES_SAMPLE_IDS_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_service.cpp new file mode 100644 index 00000000000..0c39439da0d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/climate_test_service.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2014-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <thread> +#include <mutex> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include <gtest/gtest.h> + +#include "climate_test_globals.hpp" + +class service_sample { +public: + service_sample(struct climate_test::service_info _service_info) : + app_(vsomeip::runtime::get()->create_application()), + blocked_(false), + running_(true), + is_offered_(false), + is_second_(false), + offer_thread_(std::bind(&service_sample::run, this)), + notify_thread_(std::bind(&service_sample::notify, this)), + service_info_(_service_info) { + } + + bool init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app_->register_state_handler( + std::bind(&service_sample::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + service_info_.service_id, + service_info_.instance_id, + service_info_.get_method_id, + std::bind(&service_sample::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler( + service_info_.service_id, + service_info_.instance_id, + service_info_.shutdown_method_id, + std::bind(&service_sample::on_shutdown_message, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_groups; + its_groups.insert(service_info_.eventgroup_id); + app_->offer_event( + service_info_.service_id, + service_info_.instance_id, + service_info_.event_id, + its_groups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN); + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + payload_ = vsomeip::runtime::get()->create_payload(); + } + + blocked_ = true; + condition_.notify_one(); + return true; + } + + void start() { + app_->start(); + } + + void stop() { + { + std::lock_guard<std::mutex> its_lock_notify(notify_mutex_); + running_ = false; + notify_condition_.notify_one(); + } + app_->clear_all_handler(); + if (std::this_thread::get_id() != offer_thread_.get_id()) { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } + } else { + offer_thread_.detach(); + } + if (std::this_thread::get_id() != notify_thread_.get_id()) { + if (notify_thread_.joinable()) { + notify_thread_.join(); + } + } else { + notify_thread_.detach(); + } + app_->stop(); + } + + void offer() { + std::lock_guard<std::mutex> its_lock(notify_mutex_); + app_->offer_service(service_info_.service_id, service_info_.instance_id); + is_offered_ = true; + notify_condition_.notify_one(); + } + + void stop_offer() { + std::lock_guard<std::mutex> its_lock(notify_mutex_); + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + is_offered_ = false; + notify_condition_.notify_one(); + } + + void on_state(vsomeip::state_type_e _state) { + std::cout << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered.") << std::endl; + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + // Triger second part of the test, offer and stop offer service + (void)_message; + stop_offer(); + std::this_thread::sleep_for(climate_test::OFFER_CYCLE_INTERVAL); + std::lock_guard<std::mutex> its_lock(message_mutex_); + is_second_ = true; + notify_condition_.notify_one(); + } + + void on_shutdown_message(const std::shared_ptr<vsomeip::message> &_message) { + // Test concluded, stop the service + (void)_message; + stop_offer(); + stop(); + } + + void run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); + std::unique_lock<std::mutex> its_lock_message(message_mutex_); + while (running_ && !is_second_) { + notify_condition_.wait(its_lock_message); + } + + // Offer and stop offer service with 1 second interval + bool is_offer(true); + for (uint8_t i = 0; i < 3; ++i) { + if (is_offer) { + offer(); + } + else { + stop_offer(); + } + is_offer = !is_offer; + std::this_thread::sleep_for(climate_test::OFFER_CYCLE_INTERVAL); + } + } + + void notify() { + + vsomeip::byte_t its_data[]{ 0x00, 0x01, 0x02, 0x03, 0x04}; + uint32_t its_size = 5; + + while (running_) { + std::unique_lock<std::mutex> its_lock(notify_mutex_); + while (!is_offered_ && running_) { + notify_condition_.wait(its_lock); + } + while (is_offered_ && running_) { + { + std::lock_guard<std::mutex> its_lock(payload_mutex_); + payload_->set_data(its_data, its_size); + + VSOMEIP_INFO << "\nSERVICE SIDE -> " << "Setting event (Length=" << std::dec << its_size << ")." << std::endl; + app_->notify(service_info_.service_id, service_info_.instance_id, service_info_.event_id, payload_); + } + + notify_condition_.wait_for(its_lock, std::chrono::seconds(climate_test::OFFER_CYCLE_INTERVAL)); + } + } + } + +private: + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool running_; + + std::mutex notify_mutex_; + std::condition_variable notify_condition_; + bool is_offered_; + + std::mutex message_mutex_; + bool is_second_; + + std::mutex payload_mutex_; + std::shared_ptr<vsomeip::payload> payload_; + + // blocked_ / is_offered_ must be initialized before starting the threads! + std::thread offer_thread_; + std::thread notify_thread_; + + struct climate_test::service_info service_info_; +}; + + +TEST(someip_subscribe_notify_test_example, run_service) +{ + service_sample its_sample(climate_test::service); + + if (its_sample.init()) { + its_sample.start(); + } +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master.json.in new file mode 100644 index 00000000000..3d1976f787d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master.json.in @@ -0,0 +1,81 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1344" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x0778", + "is_field" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x0779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ], + "is_multicast" : "true" + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master_starter.sh.in new file mode 100755 index 00000000000..42540f4452d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_master_starter.sh.in @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=service-sample +export VSOMEIP_CONFIGURATION=climate_test_master.json +./climate_test_service & + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting climate_test_slave_starter.sh on slave LXC with parameters" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/regression_tests; ./climate_test_slave_starter.sh \"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./climate_test_slave_starter.sh" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** climate_test_slave_starter.sh +** from an external host to successfully complete this test. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave.json.in new file mode 100644 index 00000000000..faddeb1623d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave.json.in @@ -0,0 +1,81 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1344" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509", + "multicast" : + { + "address" : "224.225.226.233", + "port" : "32344" + }, + "events" : + [ + { + "event" : "0x0777", + "is_field" : "true", + "update-cycle" : 2000 + }, + { + "event" : "0x0778", + "is_field" : "true", + "update-cycle" : 0 + }, + { + "event" : "0x0779", + "is_field" : "true" + } + ], + "eventgroups" : + [ + { + "eventgroup" : "0x4455", + "events" : [ "0x777", "0x778" ] + }, + { + "eventgroup" : "0x4465", + "events" : [ "0x778", "0x779" ], + "is_multicast" : "true" + }, + { + "eventgroup" : "0x4555", + "events" : [ "0x777", "0x779" ] + } + ] + } + ], + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave_starter.sh.in new file mode 100755 index 00000000000..0b6d0feab6f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/regression_tests/conf/climate_test_slave_starter.sh.in @@ -0,0 +1,34 @@ +#!/bin/bash +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +# Start the services +export VSOMEIP_CONFIGURATION=climate_test_slave.json +export VSOMEIP_APPLICATION_NAME=client-sample +./climate_test_client & + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/CMakeLists.txt new file mode 100644 index 00000000000..d603acf8b94 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(restart_routing_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + restart_routing_test_autoconfig.json + restart_routing_test_client.json + restart_routing_test_client_start.sh + restart_routing_test_service.json + restart_routing_test_service_start.sh + restart_routing_test_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(restart_routing_test_service + restart_routing_test_service.cpp +) + +# Add test executable. +add_executable(restart_routing_test_client + restart_routing_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + restart_routing_test_service + restart_routing_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME restart_routing_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/restart_routing_test_starter.sh + TIMEOUT 600 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_autoconfig.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_autoconfig.json.in new file mode 100644 index 00000000000..fc55e4a42c4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_autoconfig.json.in @@ -0,0 +1,24 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client.json.in new file mode 100644 index 00000000000..c5444590c70 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client.json.in @@ -0,0 +1,48 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "restart_routing_test_client1", + "id" : "0x1343" + }, + { + "name" : "restart_routing_test_client2", + "id" : "0x1344" + }, + { + "name" : "restart_routing_test_client3", + "id" : "0x1345" + }, + { + "name" : "restart_routing_test_client4", + "id" : "0x1346" + } + ], + "services" : + [ + ], + + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client_start.sh.in new file mode 100755 index 00000000000..de944b9689a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_client_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service.json.in new file mode 100644 index 00000000000..4e07e6640b6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service.json.in @@ -0,0 +1,44 @@ +{ + "unicast" : "127.0.0.1", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "routingmanagerd", + "id" : "0x0815" + }, + { + "name" : "restart_routing_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service_start.sh.in new file mode 100755 index 00000000000..b82be7cd8fa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_starter.sh.in new file mode 100755 index 00000000000..456572c5949 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/conf/restart_routing_test_starter.sh.in @@ -0,0 +1,342 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# NOW WITHOUT JSON +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with auto configuration " +echo "----------------------------------------------" +echo "----------------------------------------------" + +export VSOMEIP_CONFIGURATION=restart_routing_test_autoconfig.json + +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! +echo "Launched Daemon with PID: $DAEMON_PID" +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERVICE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let routingmanagerd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +echo "----------------------------------------------" +echo " restart routingmanagerd " +echo "----------------------------------------------" +sleep 2 + +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! + +wait $SERVICE_PID || ((FAIL+=1)) +echo "Service Finished Successfully" +wait $CLIENT1_PID || ((FAIL+=1)) +echo "Client1 Finished Successfully" +wait $CLIENT2_PID || ((FAIL+=1)) +echo "Client2 Finished Successfully" +wait $CLIENT3_PID || ((FAIL+=1)) +echo "Client3 Finished Successfully" +wait $CLIENT4_PID || ((FAIL+=1)) +echo "Client4 Finished Successfully" + +kill $DAEMON_PID +wait $DAEMON_PID +echo "Daemon Finished Successfully" + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Success Part1" +else + echo "Test Failed Part1" + exit 1 +fi + +# NOW WITHOUT VSOMEIPD +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with auto configuration no deamon " +echo "----------------------------------------------" +echo "----------------------------------------------" + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERVICE_PID=$! +echo "Launched Service as Daemon with PID: $SERVICE_PID" +sleep 2 + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let service (routing) crash (kill -9) " +echo "----------------------------------------------" +kill -9 $SERVICE_PID +echo "----------------------------------------------" +echo " restart service (routing) " +echo "----------------------------------------------" +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +./restart_routing_test_service & +SERVICE_PID=$! + +wait $SERVICE_PID || ((FAIL+=1)) +echo "Service Finished Successfully" +wait $CLIENT1_PID || ((FAIL+=1)) +echo "Client1 Finished Successfully" +wait $CLIENT2_PID || ((FAIL+=1)) +echo "Client2 Finished Successfully" +wait $CLIENT3_PID || ((FAIL+=1)) +echo "Client3 Finished Successfully" +wait $CLIENT4_PID || ((FAIL+=1)) +echo "Client4 Finished Successfully" + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Success Part2" +else + echo "Test Failed Part2" + exit 1 +fi + + +echo "----------------------------------------------" +echo "----------------------------------------------" +echo " Run test with json configuration " +echo "----------------------------------------------" +echo "----------------------------------------------" + + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! +echo "Launched Daemon with PID: $DAEMON_PID" +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERVICE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let routingmanagerd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +echo "----------------------------------------------" +echo " restart routingmanagerd " +echo "----------------------------------------------" +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! + +wait $SERVICE_PID || ((FAIL+=1)) +echo "Service Finished Successfully" +wait $CLIENT1_PID || ((FAIL+=1)) +echo "Client1 Finished Successfully" +wait $CLIENT2_PID || ((FAIL+=1)) +echo "Client2 Finished Successfully" +wait $CLIENT3_PID || ((FAIL+=1)) +echo "Client3 Finished Successfully" +wait $CLIENT4_PID || ((FAIL+=1)) +echo "Client4 Finished Successfully" + +kill $DAEMON_PID +wait $DAEMON_PID +echo "Daemon Finished Successfully" + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Success Part3" +else + echo "Test Failed Part3" + exit 1 +fi + +echo "----------------------------------------------" +echo "----------------------------------------------" +echo "Run test with json configuration + kill service" +echo "----------------------------------------------" +echo "----------------------------------------------" + + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! +echo "Launched Daemon with PID: $DAEMON_PID" +sleep 2 + +# Start the service +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERVICE_PID=$! + +# Start the client1 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client1 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT1_PID=$! + +# Start the client2 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client2 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT2_PID=$! + +# Start the client3 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client3 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT3_PID=$! + +# Start the client4 +export VSOMEIP_APPLICATION_NAME=restart_routing_test_client4 +export VSOMEIP_CONFIGURATION=restart_routing_test_client.json +./restart_routing_test_client & +CLIENT4_PID=$! + +sleep 2 +echo "----------------------------------------------" +echo " let routingmanagerd crash (kill -9) " +echo "----------------------------------------------" +kill -9 $DAEMON_PID +sleep 1 +echo "----------------------------------------------" +echo " let service crash (kill -9) " +echo "----------------------------------------------" +kill -9 $SERVICE_PID +echo "----------------------------------------------" +echo " restart routingmanagerd " +echo "----------------------------------------------" +sleep 2 + +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +../../../examples/routingmanagerd/routingmanagerd & +DAEMON_PID=$! + +echo "----------------------------------------------" +echo " restart service " +echo "----------------------------------------------" +sleep 1 + +# Start the service again +export VSOMEIP_APPLICATION_NAME=restart_routing_test_service +export VSOMEIP_CONFIGURATION=restart_routing_test_service.json +./restart_routing_test_service & +SERVICE_PID=$! + +wait $SERVICE_PID || ((FAIL+=1)) +echo "Service Finished Successfully" +wait $CLIENT1_PID || ((FAIL+=1)) +echo "Client1 Finished Successfully" +wait $CLIENT2_PID || ((FAIL+=1)) +echo "Client2 Finished Successfully" +wait $CLIENT3_PID || ((FAIL+=1)) +echo "Client3 Finished Successfully" +wait $CLIENT4_PID || ((FAIL+=1)) +echo "Client4 Finished Successfully" + +kill $DAEMON_PID +wait $DAEMON_PID +echo "Daemon Finished Successfully" + +# Check if client and server both exited sucessfully and the service didnt't +# have any open tcp/udp sockets +if [ $FAIL -eq 0 ] +then + echo "Test Success Part4" + exit 0 +else + echo "Test Failed Part4" + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.cpp new file mode 100644 index 00000000000..7d6a001a466 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "restart_routing_test_client.hpp" + +routing_restart_test_client::routing_restart_test_client() + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&routing_restart_test_client::run, this)), + received_responses_(0) { + +} + +bool routing_restart_test_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&routing_restart_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&routing_restart_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&routing_restart_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void routing_restart_test_client::start() { + VSOMEIP_INFO << "Starting..."; + + app_->start(); +} + +void routing_restart_test_client::stop() { + VSOMEIP_INFO << "Stopping..."; + + shutdown_service(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->clear_all_handler(); + app_->stop(); +} + +void routing_restart_test_client::on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + } +} + +void routing_restart_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if(is_available_ && !_is_available) { + is_available_ = false; + } + else if(_is_available && !is_available_) { + is_available_ = true; + condition_.notify_one(); + } + } +} + +void routing_restart_test_client::on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + + if (_response->get_service() == vsomeip_test::TEST_SERVICE_SERVICE_ID && + _response->get_instance() == vsomeip_test::TEST_SERVICE_INSTANCE_ID) { + + received_responses_++; + if (received_responses_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + all_responses_received_.set_value(); + } + } +} + +void routing_restart_test_client::run() { + std::uint32_t its_sent_requests(0); + bool its_availability_timeout = false; + while (its_sent_requests < vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_available_) + { + if (!condition_.wait_for(its_lock, std::chrono::milliseconds(10000), + [this] { return is_available_; })) { + VSOMEIP_WARNING << "Service not available for 10s. Quit waiting"; + its_availability_timeout = true; + break; + } + if (its_sent_requests > 0 && received_responses_ > 0 + && its_sent_requests > received_responses_) { + VSOMEIP_WARNING << "Sent/Recv messages mismatch (" << its_sent_requests << "/" + << received_responses_ + << ") : Resending non-responded requests"; + its_sent_requests = received_responses_; + } + } + } + + if (its_availability_timeout) { + break; + } + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + app_->send(request); + + its_sent_requests++; + VSOMEIP_INFO << "Sent request " << its_sent_requests; + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + if (std::future_status::ready == all_responses_received_.get_future().wait_for(std::chrono::milliseconds(10000))) { + EXPECT_EQ(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS, + received_responses_); + VSOMEIP_WARNING << "Received all answers"; + } else { + ADD_FAILURE() << "Didn't receive all responses within time"; + } + + stop(); +} + +void routing_restart_test_client::join_sender_thread() +{ + if (sender_.joinable()) { + sender_.join(); + } +} + +void routing_restart_test_client::shutdown_service() { + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request); +} + +TEST(someip_restart_routing_test, request_response_over_restart) +{ + routing_restart_test_client test_client; + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.hpp new file mode 100644 index 00000000000..8a7c9e70dfd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_client.hpp @@ -0,0 +1,53 @@ + +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef RESTART_ROUTING_TEST_CLIENT_HPP +#define RESTART_ROUTING_TEST_CLIENT_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <atomic> +#include <future> + +class routing_restart_test_client { +public: + routing_restart_test_client(); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic<std::uint32_t> received_responses_; + std::promise<void> all_responses_received_; +}; + +#endif // RESTART_ROUTING_TEST_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.cpp new file mode 100644 index 00000000000..c8b19271263 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.cpp @@ -0,0 +1,156 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "restart_routing_test_service.hpp" + +routing_restart_test_service::routing_restart_test_service() : + app_(vsomeip::runtime::get()->create_application()), is_registered_(false), blocked_(false), + init_shutdown_(false), all_received_(false), shutdown_counter_(0), + offer_thread_(std::bind(&routing_restart_test_service::run, this)) { } + +bool routing_restart_test_service::init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&routing_restart_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&routing_restart_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&routing_restart_test_service::on_state, this, + std::placeholders::_1)); + return true; +} + +void routing_restart_test_service::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void routing_restart_test_service::stop() { + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void routing_restart_test_service::join_offer_thread() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void routing_restart_test_service::offer() { + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void routing_restart_test_service::stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void routing_restart_test_service::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + if(!is_registered_) { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else { + is_registered_ = false; + } +} + +void routing_restart_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) { + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _request->get_method()); + received_counter_[_request->get_client()]++; + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) << std::setfill('0') + << std::hex << _request->get_client() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _request->get_session() << "] : " << std::dec + << received_counter_[_request->get_client()]; + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); + + { + std::lock_guard<std::mutex> its_guard(number_of_received_messages_mutex_); + number_of_received_messages_++; + if (number_of_received_messages_ + == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS) { + VSOMEIP_INFO << "Received all messages!"; + } + } +} + +void routing_restart_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) { + VSOMEIP_INFO << "Shutdown Service requested by 0x" << std::setw(4) << std::setfill('0') + << std::hex << _request->get_client(); + { + std::lock_guard<std::mutex> its_guard_counter(counter_mutex_); + shutdown_counter_++; + if (shutdown_counter_ == 1) { + std::lock_guard<std::mutex> its_guard(shutdown_mutex_); + init_shutdown_ = true; + init_shutdown_condition_.notify_one(); + } else if (shutdown_counter_ == vsomeip_test::NUMBER_OF_CLIENTS_TO_REQUEST_SHUTDOWN) { + std::lock_guard<std::mutex> its_guard(shutdown_mutex_); + all_received_ = true; + execute_shutdown_condition_.notify_one(); + } + } +} + +void routing_restart_test_service::run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); + std::unique_lock<std::mutex> its_shutdown_lock(shutdown_mutex_); + init_shutdown_condition_.wait(its_shutdown_lock, [this] { return init_shutdown_; }); + if (!execute_shutdown_condition_.wait_for(its_shutdown_lock, std::chrono::milliseconds(5000), + [this] { return all_received_; })) { + VSOMEIP_WARNING + << "Timeout reached : Not all clients requested shutdown. Stopping Service anyway"; + } + stop(); +} + +TEST(someip_restart_routing_test, send_response_for_every_request) { + routing_restart_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.hpp new file mode 100644 index 00000000000..18c80256180 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/restart_routing_tests/restart_routing_test_service.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef RESTART_ROUTING_TEST_SERVICE_HPP +#define RESTART_ROUTING_TEST_SERVICE_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> + +class routing_restart_test_service { +public: + routing_restart_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + std::condition_variable init_shutdown_condition_; + std::condition_variable execute_shutdown_condition_; + bool blocked_; + bool init_shutdown_; + bool all_received_; + std::mutex shutdown_mutex_; + std::mutex counter_mutex_; + std::uint32_t shutdown_counter_; + std::map<std::uint16_t, std::uint32_t> received_counter_; + + std::mutex number_of_received_messages_mutex_; + std::uint32_t number_of_received_messages_; + + std::thread offer_thread_; +}; + +#endif // RESTART_ROUTING_TEST_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/CMakeLists.txt new file mode 100644 index 00000000000..3c9626be729 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(routing_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + external_local_routing_test_client_external.json + external_local_routing_test_client_external_start.sh + external_local_routing_test_service.json + external_local_routing_test_service_start.sh + external_local_routing_test_starter.sh + local_routing_test_client.json + local_routing_test_client_start.sh + local_routing_test_service.json + local_routing_test_service_start.sh + local_routing_test_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(local_routing_test_service + local_routing_test_service.cpp +) + +# Add test executable. +add_executable(local_routing_test_client + local_routing_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + local_routing_test_service + local_routing_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME local_routing_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/local_routing_test_starter.sh +) + +if(NOT TESTS_BAT) + + # Add test executable. + add_executable(external_local_routing_test_service + external_local_routing_test_service.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + external_local_routing_test_service + ) + targets_add_default_dependencies("${executables}") + targets_link_default_libraries("${executables}") + + # Add custom test command. + add_custom_test( + NAME external_local_routing_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/external_local_routing_test_starter.sh + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external.json.in new file mode 100644 index 00000000000..e6b0e9df9e1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external.json.in @@ -0,0 +1,47 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "diagnosis" : "0x16", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "external_local_routing_test_client_external", + "id" : "0x1644" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + + "routing": { + "enabled": false, + "host": "external_local_routing_test_client_external" + }, + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external_start.sh.in new file mode 100755 index 00000000000..098c777f7de --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_client_external_start.sh.in @@ -0,0 +1,17 @@ +#!/bin/bash -ex +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_routing_test_client_external +export VSOMEIP_CONFIGURATION=external_local_routing_test_client_external.json +./local_routing_test_client & +client=$! + +for _ in {1..100} +do + find /tmp -ls + lsof -nw -p "$client" || continue +done +wait "$client" diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service.json.in new file mode 100644 index 00000000000..d87882b169f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service.json.in @@ -0,0 +1,42 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "diagnosis":"0x12", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "external_local_routing_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unreliable" : "30509" + } + ], + + "routing" : "external_local_routing_test_service", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service_start.sh.in new file mode 100755 index 00000000000..81b2ef1458f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=external_local_routing_test_service +export VSOMEIP_CONFIGURATION=external_local_routing_test_service.json +./external_local_routing_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_starter.sh.in new file mode 100755 index 00000000000..b47d771e65f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/external_local_routing_test_starter.sh.in @@ -0,0 +1,121 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_open () +{ + # Check that the service does listen on at least one TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -lt 1 ] + then + ((FAIL+=1)) + fi +} + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the service does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + ((FAIL+=1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + ((FAIL+=1)) + fi +} + +# Start the service +export VSOMEIP_APPLICATION_NAME=external_local_routing_test_service +export VSOMEIP_CONFIGURATION=external_local_routing_test_service.json +./external_local_routing_test_service & +SERIVCE_PID=$! +sleep 1; + +check_tcp_udp_sockets_are_open $SERIVCE_PID + +# Start the client (we reuse the one from the local_routing_test to check +# the local routing functionality). +export VSOMEIP_APPLICATION_NAME=local_routing_test_client +export VSOMEIP_CONFIGURATION=local_routing_test_client.json +./local_routing_test_client & +CLIENT_PID=$! + +check_tcp_udp_sockets_are_open $SERIVCE_PID +sleep 1 +check_tcp_udp_sockets_are_closed $CLIENT_PID + +# wait that local client finishes +sleep 2 + +# Display a message to show the user that he must now call the external client +# to finish the test successfully +kill -0 $CLIENT_PID &> /dev/null +CLIENT_STILL_THERE=$? +if [ $CLIENT_STILL_THERE -ne 0 ] +then + if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external_local_routing_test_starter.sh on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/routing_tests; ./external_local_routing_test_client_external_start.sh\"" & + echo "remote ssh job id: $!" + elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./external_local_routing_test_client_external_start.sh" & + else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** external_local_routing_test_client_external_start.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** external_local_routing_test_client_external.json and +** external_local_routing_test_service.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message + fi +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if client and server both exited sucessfully and the service didnt't +# have any open +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client.json.in new file mode 100644 index 00000000000..e0756b96040 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client.json.in @@ -0,0 +1,38 @@ +{ + "unicast" : "127.0.0.1", + "netmask" : "255.255.255.0", + "diagnosis":"0x12", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "true", + "path" : "/var/log/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "local_routing_test_client", + "id" : "0x1255" + } + ], + + "services" : + [ + ], + + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30491", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client_start.sh.in new file mode 100755 index 00000000000..ed4023e7243 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_client_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=local_routing_test_client +export VSOMEIP_CONFIGURATION=local_routing_test_client.json +./local_routing_test_client diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service.json.in new file mode 100644 index 00000000000..20c77674138 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service.json.in @@ -0,0 +1,41 @@ +{ + "unicast" : "127.0.0.1", + "diagnosis":"0x12", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : + { + "enable" : "false", + "path" : "/tmp/vsomeip.log" + }, + + "dlt" : "true" + }, + + "applications" : + [ + { + "name" : "local_routing_test_service", + "id" : "0x1277" + } + ], + + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "false", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service_start.sh.in new file mode 100755 index 00000000000..c59364c7a50 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_service_start.sh.in @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_APPLICATION_NAME=local_routing_test_service +export VSOMEIP_CONFIGURATION=local_routing_test_service.json +./local_routing_test_service diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_starter.sh.in new file mode 100755 index 00000000000..17c3d1e9adc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/conf/local_routing_test_starter.sh.in @@ -0,0 +1,76 @@ +#!/bin/sh +# Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the client and service with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start two binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs client +# and service and checks that both exit sucessfully. + +FAIL=0 + +# Parameter 1: the pid to check +check_tcp_udp_sockets_are_closed () +{ + # Check that the service does not listen on any TCP/UDP socket + # or has any active connection via a TCP/UDP socket + # awk is used to avoid the case when a inode number is the same as a PID. The awk + # program filters the netstat output down to the protocol (1st field) and + # the PID/Program name (last field) fields. + SERVICE_SOCKETS_LISTENING=$(netstat -tulpen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_LISTENING -ne 0 ] + then + ((FAIL+=1)) + fi + + SERVICE_SOCKETS_CONNECTED=$(netstat -tupen 2> /dev/null | awk '{print $1 "\t" $NF}' | grep $1 | wc -l) + if [ $SERVICE_SOCKETS_CONNECTED -ne 0 ] + then + ((FAIL+=1)) + fi +} + +export VSOMEIP_CONFIGURATION=local_routing_test_service.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +# Start the service +export VSOMEIP_APPLICATION_NAME=local_routing_test_service +./local_routing_test_service & +SERIVCE_PID=$! +WAIT_PID_ONE=$! +sleep 1; + +check_tcp_udp_sockets_are_closed $SERIVCE_PID + +# Start the client +export VSOMEIP_APPLICATION_NAME=local_routing_test_client +export VSOMEIP_CONFIGURATION=local_routing_test_client.json +./local_routing_test_client & +CLIENT_PID=$! +WAIT_PID_TWO=$! + +check_tcp_udp_sockets_are_closed $SERIVCE_PID +check_tcp_udp_sockets_are_closed $CLIENT_PID + +# Wait until client and service are finished +# Fail gets incremented if either client or service exit +# with a non-zero exit code +wait $WAIT_PID_ONE || ((FAIL+=1)) +wait $WAIT_PID_TWO || ((FAIL+=1)) + +kill $PID_VSOMEIPD +sleep 1 + +# Check if client and server both exited successfully and the service didnt't +# have any open +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.cpp new file mode 100644 index 00000000000..c90f17b12bb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "external_local_routing_test_service.hpp" + +external_local_routing_test_service::external_local_routing_test_service(bool _use_static_routing) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + use_static_routing_(_use_static_routing), + blocked_(false), + number_received_messages_local_(0), + number_received_messages_external_(0), + offer_thread_(std::bind(&external_local_routing_test_service::run, this)) +{ +} + +bool external_local_routing_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&external_local_routing_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&external_local_routing_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&external_local_routing_test_service::on_state, this, + std::placeholders::_1)); + + VSOMEIP_INFO << "Static routing " << (use_static_routing_ ? "ON" : "OFF"); + return true; +} + +void external_local_routing_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void external_local_routing_test_service::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void external_local_routing_test_service::join_offer_thread() +{ + offer_thread_.join(); +} + +void external_local_routing_test_service::offer() +{ + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void external_local_routing_test_service::stop_offer() +{ + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void external_local_routing_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + std::lock_guard<std::mutex> its_lock(mutex_); + is_registered_ = true; + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void external_local_routing_test_service::on_message( + const std::shared_ptr<vsomeip::message>& _request) +{ + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "]"; + + ASSERT_EQ(_request->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID); + ASSERT_EQ(_request->get_method(), vsomeip_test::TEST_SERVICE_METHOD_ID); + + // Check the protocol version this shall be set to 0x01 according to the spec. + // TR_SOMEIP_00052 + ASSERT_EQ(_request->get_protocol_version(), 0x01); + // Check the message type this shall be 0xx (REQUEST) according to the spec. + // TR_SOMEIP_00055 + ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST); + + if(_request->get_client() == vsomeip_test::TEST_CLIENT_CLIENT_ID) + { + number_received_messages_local_++; + // check the session id. + ASSERT_EQ(_request->get_session(), + static_cast<vsomeip::session_t>(number_received_messages_local_)); + } + else if (_request->get_client() == vsomeip_test::TEST_CLIENT_EXTERNAL_CLIENT_ID) + { + number_received_messages_external_++; + // check the session id. + ASSERT_EQ(_request->get_session(), + static_cast<vsomeip::session_t>(number_received_messages_external_)); + } + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); + + if(number_received_messages_local_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + && number_received_messages_external_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND) + { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } + ASSERT_LT(number_received_messages_local_, + vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + 1); + ASSERT_LT(number_received_messages_external_, + vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + 1); +} + +void external_local_routing_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + blocked_ = false; + if(use_static_routing_) + { + offer(); + } + + while (!blocked_) { + condition_.wait(its_lock); + } + + std::thread t2([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 2));}); + t2.join(); + app_->stop(); +} + +TEST(someip_external_local_routing_test, receive_ten_messages_over_local_and_external_socket) +{ + bool use_static_routing = true; + external_local_routing_test_service test_service(use_static_routing); + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.hpp new file mode 100644 index 00000000000..2499bc8403d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/external_local_routing_test_service.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EXTERNALLOCALROUTINGTESTSERVICE_HPP_ +#define EXTERNALLOCALROUTINGTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class external_local_routing_test_service +{ +public: + external_local_routing_test_service(bool _use_static_routing); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + bool use_static_routing_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_received_messages_local_; + std::uint32_t number_received_messages_external_; + std::thread offer_thread_; +}; + +#endif /* EXTERNALLOCALROUTINGTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.cpp new file mode 100644 index 00000000000..f7f83c3249f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.cpp @@ -0,0 +1,160 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "local_routing_test_client.hpp" + +local_routing_test_client::local_routing_test_client(bool _use_tcp) : + app_(vsomeip::runtime::get()->create_application()), + request_(vsomeip::runtime::get()->create_request(_use_tcp)), + blocked_(false), + is_available_(false), + number_of_messages_to_send_(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND), + number_of_sent_messages_(0), + number_of_acknowledged_messages_(0), + sender_(std::bind(&local_routing_test_client::run, this)) +{ +} + +bool local_routing_test_client::init() +{ + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&local_routing_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&local_routing_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + return true; +} + +void local_routing_test_client::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void local_routing_test_client::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void local_routing_test_client::join_sender_thread(){ + sender_.join(); + + ASSERT_EQ(number_of_sent_messages_, number_of_acknowledged_messages_); +} + +void local_routing_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) +{ + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) + { + if(is_available_ && !_is_available) + { + is_available_ = false; + } + else if(_is_available && !is_available_) + { + is_available_ = true; + send(); + } + } +} + +void local_routing_test_client::on_message(const std::shared_ptr<vsomeip::message>& _response) +{ + VSOMEIP_INFO << "Received a response from Service [" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" << std::setw(4) + << std::setfill('0') << std::hex << _response->get_session() << "]"; + number_of_acknowledged_messages_++; + if(number_of_acknowledged_messages_ == number_of_messages_to_send_) { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); + } +} + +void local_routing_test_client::send() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + condition_.notify_one(); +} + +void local_routing_test_client::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + { + condition_.wait(its_lock); + } + blocked_ = false; + request_->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request_->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request_->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + for (uint32_t i = 0; i < number_of_messages_to_send_; i++) + { + app_->send(request_); + VSOMEIP_INFO << "Client/Session [" << std::setw(4) << std::setfill('0') + << std::hex << request_->get_client() << "/" << std::setw(4) + << std::setfill('0') << std::hex << request_->get_session() + << "] sent a request to Service [" << std::setw(4) + << std::setfill('0') << std::hex << request_->get_service() + << "." << std::setw(4) << std::setfill('0') << std::hex + << request_->get_instance() << "]"; + number_of_sent_messages_++; + } + blocked_ = false; + // wait until all messages have been acknowledged + while (!blocked_) + { + condition_.wait(its_lock); + } + stop(); +} + +TEST(someip_local_routing_test, send_ten_messages_to_service_and_receive_reply) +{ + bool use_tcp = false; + local_routing_test_client test_client_(use_tcp); + if (test_client_.init()) { + test_client_.start(); + test_client_.join_sender_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.hpp new file mode 100644 index 00000000000..09af0bf06bb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_client.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LOCALROUTINGTESTCLIENT_HPP_ +#define LOCALROUTINGTESTCLIENT_HPP_ + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class local_routing_test_client +{ +public: + local_routing_test_client(bool _use_tcp); + bool init(); + void start(); + void stop(); + void join_sender_thread(); + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + void send(); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + std::shared_ptr<vsomeip::message> request_; + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + bool is_available_; + std::uint32_t number_of_messages_to_send_; + std::uint32_t number_of_sent_messages_; + std::uint32_t number_of_acknowledged_messages_; + std::thread sender_; +}; + +#endif /* LOCALROUTINGTESTCLIENT_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.cpp new file mode 100644 index 00000000000..5d659e2648b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "local_routing_test_service.hpp" + +local_routing_test_service::local_routing_test_service(bool _use_static_routing) : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + use_static_routing_(_use_static_routing), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&local_routing_test_service::run, this)) +{ +} + +bool local_routing_test_service::init() +{ + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&local_routing_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&local_routing_test_service::on_state, this, + std::placeholders::_1)); + + VSOMEIP_INFO << "Static routing " << (use_static_routing_ ? "ON" : "OFF"); + return true; +} + +void local_routing_test_service::start() +{ + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void local_routing_test_service::stop() +{ + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void local_routing_test_service::join_offer_thread() +{ + offer_thread_.join(); +} + +void local_routing_test_service::offer() +{ + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void local_routing_test_service::stop_offer() +{ + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void local_routing_test_service::on_state(vsomeip::state_type_e _state) +{ + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) + { + if(!is_registered_) + { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else + { + is_registered_ = false; + } +} + +void local_routing_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) +{ + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "]"; + + number_of_received_messages_++; + + ASSERT_EQ(_request->get_service(), vsomeip_test::TEST_SERVICE_SERVICE_ID); + ASSERT_EQ(_request->get_method(), vsomeip_test::TEST_SERVICE_METHOD_ID); + + // Check the protocol version this shall be set to 0x01 according to the spec. + // TR_SOMEIP_00052 + ASSERT_EQ(_request->get_protocol_version(), 0x01); + // Check the message type this shall be 0xx (REQUEST) according to the spec. + // TR_SOMEIP_00055 + ASSERT_EQ(_request->get_message_type(), vsomeip::message_type_e::MT_REQUEST); + + // check the session id. + ASSERT_EQ(_request->get_session(), static_cast<vsomeip::session_t>(number_of_received_messages_)); + + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); + + if(number_of_received_messages_ >= vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND) + { + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ =true; + condition_.notify_one(); + } + ASSERT_LT(number_of_received_messages_, + vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND + 1); +} + +void local_routing_test_service::run() +{ + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + blocked_ = false; + if(use_static_routing_) + { + offer(); + } + while (!blocked_) + condition_.wait(its_lock); + + std::thread t2([](){ std::this_thread::sleep_for(std::chrono::microseconds(1000000 * 5));}); + t2.join(); + app_->stop(); +} + +TEST(someip_local_routing_test, receive_ten_messages_over_local_uds_socket) +{ + bool use_static_routing = true; + local_routing_test_service test_service(use_static_routing); + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.hpp new file mode 100644 index 00000000000..109dade4049 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/routing_tests/local_routing_test_service.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LOCALROUTINGTESTSERVICE_HPP_ +#define LOCALROUTINGTESTSERVICE_HPP_ +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class local_routing_test_service +{ +public: + local_routing_test_service(bool _use_static_routing); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + bool use_static_routing_; + + bool blocked_; + std::uint32_t number_of_received_messages_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; +}; + +#endif /* LOCALROUTINGTESTSERVICE_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/CMakeLists.txt new file mode 100644 index 00000000000..c3f678328ee --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(second_address_tests LANGUAGES CXX) + +# Configure necessary files into build folder. +set(configuration_files + second_address_test_master_client.json + second_address_test_master_service_udp.json + second_address_test_master_starter.sh + second_address_test_slave_client.json + second_address_test_slave_service_udp.json + second_address_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(second_address_test_service + second_address_test_service.cpp +) + +# Add test executable. +add_executable(second_address_test_client + second_address_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + second_address_test_service + second_address_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME second_address_test_second_ip_address_service_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/second_address_test_master_starter.sh SERVICE UDP + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME second_address_test_second_ip_address_client_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/second_address_test_master_starter.sh CLIENT UDP + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_client.json.in new file mode 100644 index 00000000000..4df776d96e0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_client.json.in @@ -0,0 +1,32 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "second_address_test_client", + "id" : "0x1210", + "max_dispatch_time" : "1000" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_service_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_service_udp.json.in new file mode 100644 index 00000000000..c42083dddcd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_service_udp.json.in @@ -0,0 +1,40 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "second_address_test_service", + "id" : "0x3489", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30001" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_starter.sh.in new file mode 100755 index 00000000000..66f7d5600eb --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_master_starter.sh.in @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +if [ $# -lt 2 ] +then + echo "Please pass a operation and communication mode to this script." + echo "For example: $0 SERVICE UDP" + echo "Valid operation modes include [SERVICE, CLIENT]" + echo "Valid communication modes include [UDP, TCP]" + exit 1 +fi + +OPERATIONMODE=$1 +COMMUNICATIONMODE=$2 + +if [ "$OPERATIONMODE" = "SERVICE" ]; then + MASTER_APPLICATION=second_address_test_service + SLAVE_OPERATIONMODE="CLIENT" + + if [ "$COMMUNICATIONMODE" = "TCP" ]; then + export VSOMEIP_CONFIGURATION=second_address_test_master_service_tcp.json + elif [ "$COMMUNICATIONMODE" = "UDP" ]; then + export VSOMEIP_CONFIGURATION=second_address_test_master_service_udp.json + fi + +elif [ "$OPERATIONMODE" = "CLIENT" ]; then + MASTER_APPLICATION=second_address_test_client + SLAVE_OPERATIONMODE="SERVICE" + export VSOMEIP_CONFIGURATION=second_address_test_master_client.json +fi + +rm -f /tmp/vsomeip* + +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +./$MASTER_APPLICATION $COMMUNICATIONMODE & +PID_MASTER=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting offer test on slave LXC second_address_test_slave_starter.sh" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/second_address_tests; ./second_address_test_slave_starter.sh $SLAVE_OPERATIONMODE $COMMUNICATIONMODE\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS; sleep 10; ./second_address_test_slave_starter.sh $SLAVE_OPERATIONMODE $COMMUNICATIONMODE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** second_address_test_slave_starter.sh $COMMUNICATIONMODE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** second_address_test_slave_{udp,tcp}.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all slaves are finished +for job in $PID_MASTER +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_client.json.in new file mode 100644 index 00000000000..667198053af --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_client.json.in @@ -0,0 +1,32 @@ +{ + "unicast":"@TEST_IP_SLAVE_SECOND@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "second_address_test_client", + "id" : "0x1210", + "max_dispatch_time" : "1000" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_service_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_service_udp.json.in new file mode 100644 index 00000000000..e6adfb127ae --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_service_udp.json.in @@ -0,0 +1,40 @@ +{ + "unicast":"@TEST_IP_SLAVE_SECOND@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications" : + [ + { + "name" : "second_address_test_service", + "id" : "0x3489", + "max_dispatch_time" : "1000" + } + ], + "services": + [ + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30001" + } + ], + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.50.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_starter.sh.in new file mode 100755 index 00000000000..ab2b74e8989 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/conf/second_address_test_slave_starter.sh.in @@ -0,0 +1,62 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +if [ $# -lt 2 ] +then + echo "Please pass a operation and communication mode to this script." + echo "For example: $0 CLIENT UDP" + echo "Valid operation modes include [SERVICE, CLIENT]" + echo "Valid communication modes include [UDP, TCP]" + exit 1 +fi + +OPERATIONMODE=$1 +COMMUNICATIONMODE=$2 + +# Add second IP address to interface +ip addr add @TEST_IP_SLAVE_SECOND@/32 dev eth0 + +if [ "$OPERATIONMODE" = "CLIENT" ]; then + SLAVE_APPLICATION=second_address_test_client + export VSOMEIP_CONFIGURATION=second_address_test_slave_client.json + +elif [ "$OPERATIONMODE" = "SERVICE" ]; then + SLAVE_APPLICATION=second_address_test_service + + if [ "$COMMUNICATIONMODE" = "TCP" ]; then + export VSOMEIP_CONFIGURATION=second_address_test_slave_service_tcp.json + elif [ "$COMMUNICATIONMODE" = "UDP" ]; then + export VSOMEIP_CONFIGURATION=second_address_test_slave_service_udp.json + fi +fi + +rm -f /tmp/vsomeip* + +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +./$SLAVE_APPLICATION $COMMUNICATIONMODE & +PID_SLAVE=$! + +# Wait until all slaves are finished +for job in $PID_SLAVE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# Delete second IP address +ip addr del @TEST_IP_SLAVE_SECOND@/32 dev eth0 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_client.cpp new file mode 100644 index 00000000000..72aae04ade4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_client.cpp @@ -0,0 +1,356 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "second_address_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class second_address_test_client : public vsomeip_utilities::base_logger { +public: + second_address_test_client(struct second_address_test::service_info _service_info, bool _use_tcp) : + vsomeip_utilities::base_logger("SATC", "SECOND ADDRESS TEST CLIENT"), + service_info_(_service_info), + use_tcp_(_use_tcp), + app_(vsomeip::runtime::get()->create_application("second_address_test_client")), + send_thread_(std::bind(&second_address_test_client::send, this)) { + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&second_address_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.request_method_id, + std::bind(&second_address_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + std::bind(&second_address_test_client::on_notification, this, + std::placeholders::_1, false)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.selective_event_id, + std::bind(&second_address_test_client::on_notification, this, + std::placeholders::_1, true)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&second_address_test_client::on_shutdown_method_called, this, + std::placeholders::_1)); + + // register availability for all other services and request their event. + app_->register_availability_handler(service_info_.service_id, + service_info_.instance_id, + std::bind(&second_address_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->request_service(service_info_.service_id, + service_info_.instance_id); + + app_->register_subscription_status_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + service_info_.event_id, + std::bind(&second_address_test_client::on_subscription_status_changed, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5, false)); + + app_->register_subscription_status_handler(service_info_.service_id, + service_info_.instance_id, service_info_.selective_eventgroup_id, + service_info_.selective_event_id, + std::bind(&second_address_test_client::on_subscription_status_changed, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5, true)); + + app_->start(); + } + + ~second_address_test_client() { + send_thread_.join(); + } + + void subscribe() { + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + + app_->request_event(service_info_.service_id, + service_info_.instance_id, service_info_.event_id, + its_eventgroups, vsomeip::event_type_e::ET_EVENT); + + its_eventgroups.clear(); + its_eventgroups.insert(service_info_.selective_eventgroup_id); + + app_->request_event(service_info_.service_id, + service_info_.instance_id, service_info_.selective_event_id, + its_eventgroups, vsomeip::event_type_e::ET_SELECTIVE_EVENT); + + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.eventgroup_id); + + app_->subscribe(service_info_.service_id, service_info_.instance_id, + service_info_.selective_eventgroup_id); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_DEBUG << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered" : "deregistered") << " on client."; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, + bool _is_available) { + + VSOMEIP_DEBUG << "Service [" << std::setw(4) + << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " << (_is_available ? "available":"not available") << " on client."; + + if (_is_available) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_service_available_ = false; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.request_method_id, _message->get_method()); + + std::lock_guard<std::mutex> its_lock(mutex_); + auto its_payload = _message->get_payload(); + std::uint32_t data = static_cast<std::uint32_t>(its_payload->get_data()[0]); + + EXPECT_EQ(reply_received_, data); + + wait_until_reply_received_ = false; + reply_received_++; + condition_.notify_one(); + } + + void on_notification(const std::shared_ptr<vsomeip::message> &_message, + bool _selective) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + + static vsomeip::length_t length_last_received_msg(0); + EXPECT_GT(_message->get_payload()->get_length(), length_last_received_msg); + length_last_received_msg = _message->get_payload()->get_length(); + + if (_selective) { + EXPECT_EQ(service_info_.selective_event_id, _message->get_method()); + + if (++number_selective_events_received_ == second_address_test::number_of_events_to_send) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_selective_events_received_ = false; + condition_.notify_one(); + } + } else { + EXPECT_EQ(service_info_.event_id, _message->get_method()); + + if (++number_events_received_ == second_address_test::number_of_events_to_send) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_events_received_ = false; + condition_.notify_one(); + } + } + } + + void on_subscription_status_changed(const vsomeip::service_t _service, + const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, + const vsomeip::event_t _event, + const uint16_t error_code, + bool _selective) { + + VSOMEIP_DEBUG << "Subscription status changed on client"; + + EXPECT_EQ(service_info_.service_id, _service); + EXPECT_EQ(service_info_.instance_id, _instance); + EXPECT_TRUE((error_code == 0x0u || error_code == 0x7u)); + + if (_selective) { + EXPECT_EQ(service_info_.selective_eventgroup_id, _eventgroup); + EXPECT_EQ(service_info_.selective_event_id, _event); + + if (error_code == 0x0u) { // accepted + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_selective_subscription_accepted_ = false; + condition_.notify_one(); + } + + } else { + EXPECT_EQ(service_info_.eventgroup_id, _eventgroup); + EXPECT_EQ(service_info_.event_id, _event); + + if (error_code == 0x0u) { // accepted + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_subscription_accepted_ = false; + condition_.notify_one(); + } + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + EXPECT_EQ(service_info_.shutdown_method_id, _message->get_method()); + + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_reply_received_ = false; + condition_.notify_one(); + } + + void send() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + while (wait_until_service_available_) { + condition_.wait(its_lock); + } + + auto its_message = vsomeip::runtime::get()->create_request(use_tcp_); + its_message->set_service(service_info_.service_id); + its_message->set_instance(service_info_.instance_id); + its_message->set_method(service_info_.request_method_id); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST); + + auto its_payload = vsomeip::runtime::get()->create_payload(); + + VSOMEIP_DEBUG << "Client sending request messages"; + + for (std::uint32_t index = 0; index < second_address_test::number_of_messages_to_send; index++) { + vsomeip::byte_t *msg_payload = reinterpret_cast<vsomeip::byte_t *>(&index); + its_payload->set_data(msg_payload, sizeof(index)); + its_message->set_payload(its_payload); + app_->send(its_message); + + wait_until_reply_received_ = true; + message_sent_++; + + while (wait_until_reply_received_) { + condition_.wait(its_lock); + } + } + + VSOMEIP_DEBUG << "Client subscribing events"; + + subscribe(); + while (wait_until_subscription_accepted_ || wait_until_selective_subscription_accepted_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "Client requesting event notification"; + + its_message->set_method(service_info_.notify_method_id); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_payload->set_data(&second_address_test::number_of_events_to_send, 1); + its_message->set_payload(its_payload); + app_->send(its_message); + + VSOMEIP_DEBUG << "Client waiting event notification"; + + while (wait_until_events_received_ || wait_until_selective_events_received_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "Client shutting down the service"; + + // shutdown service + its_message->set_method(service_info_.shutdown_method_id); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST); + app_->send(its_message); + + while (wait_until_shutdown_reply_received_) { + if (std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(30))) { + VSOMEIP_ERROR << "Shutdown request wasn't answered in time!"; + break; + } + } + + VSOMEIP_INFO << "Client going down"; + app_->clear_all_handler(); + app_->stop(); + } + + +private: + struct second_address_test::service_info service_info_; + bool use_tcp_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_ = true; + bool wait_until_service_available_ = true; + bool wait_until_subscription_accepted_ = true; + bool wait_until_selective_subscription_accepted_ = true; + bool wait_until_shutdown_reply_received_ = true; + bool wait_until_reply_received_ = true; + bool wait_until_events_received_ = true; + bool wait_until_selective_events_received_ = true; + std::mutex mutex_; + std::condition_variable condition_; + + std::thread send_thread_; + std::uint32_t message_sent_ = 0; + std::uint32_t reply_received_ = 0; + std::uint32_t number_events_received_ = 0; + std::uint32_t number_selective_events_received_ = 0; +}; + +static bool use_tcp = false; + +TEST(someip_event_test, communicate_using_second_address) +{ + second_address_test_client its_sample(second_address_test::service, use_tcp); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 2) { + std::cerr << "Please specify a communication mode, like: " << argv[0] << " TCP" << std::endl; + std::cerr << "Valid communication modes are UDP or TCP" << std::endl; + return 1; + } + + if (std::string("TCP")== std::string(argv[1])) { + use_tcp = true; + } else if (std::string("UDP")== std::string(argv[1])) { + use_tcp = false; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_globals.hpp new file mode 100644 index 00000000000..1909fcdd95e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_globals.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SECOND_ADDRESS_TEST_GLOBALS_HPP_ +#define SECOND_ADDRESS_TEST_GLOBALS_HPP_ + +namespace second_address_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t selective_eventgroup_id; + vsomeip::event_t selective_event_id; + vsomeip::method_t request_method_id; + vsomeip::method_t notify_method_id; + vsomeip::method_t shutdown_method_id; +}; + +struct service_info service = { 0x3333, 0x1, 0x1, 0x3301, 0x2, 0x3302, 0x1111, 0x2222, 0x1404 }; + +static constexpr std::uint32_t number_of_messages_to_send = 150; +static constexpr std::uint8_t number_of_events_to_send = 150; +} + +#endif /* SECOND_ADDRESS_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_service.cpp new file mode 100644 index 00000000000..e6346b70470 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/second_address_tests/second_address_test_service.cpp @@ -0,0 +1,256 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <map> +#include <sstream> +#include <thread> + +#include <gtest/gtest.h> +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "second_address_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class second_address_test_service : public vsomeip_utilities::base_logger { +public: + second_address_test_service(struct second_address_test::service_info _service_info) : + vsomeip_utilities::base_logger("SATS", "SECOND ADDRESS TEST SERVICE"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application("second_address_test_service")), + offer_thread_(std::bind(&second_address_test_service::run, this)) { + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&second_address_test_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.request_method_id, + std::bind(&second_address_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.notify_method_id, + std::bind(&second_address_test_service::on_notify, this, + std::placeholders::_1)); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.shutdown_method_id, + std::bind(&second_address_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + app_->register_subscription_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + std::bind(&second_address_test_service::subscription_handler, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + + app_->register_subscription_handler(service_info_.service_id, + service_info_.instance_id, service_info_.selective_eventgroup_id, + std::bind(&second_address_test_service::selective_subscription_handler, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + + app_->start(); + } + + ~second_address_test_service() { + offer_thread_.join(); + } + + void stop() { + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + app_->clear_all_handler(); + app_->stop(); + } + +private: + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered" : "deregistered") << " on service."; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called on service -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.request_method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + + std::shared_ptr<vsomeip::message> response = vsomeip::runtime::get()->create_response(_message); + response->set_payload(_message->get_payload()); + app_->send(response); + + std::lock_guard<std::mutex> its_lock(mutex_); + messages_received_++; + + if (messages_received_ == second_address_test::number_of_messages_to_send) { + wait_until_receive_messages_ = false; + condition_.notify_one(); + } + } + + void on_notify(const std::shared_ptr<vsomeip::message> &_message) { + EXPECT_EQ(service_info_.service_id, _message->get_service()); + EXPECT_EQ(service_info_.notify_method_id, _message->get_method()); + EXPECT_EQ(service_info_.instance_id, _message->get_instance()); + + auto its_payload = _message->get_payload(); + notifications_to_send_ = its_payload->get_data()[0]; + + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_notify_method_called_ = false; + condition_.notify_one(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN); + + its_eventgroups.clear(); + its_eventgroups.insert(service_info_.selective_eventgroup_id); + + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.selective_event_id, its_eventgroups, + vsomeip::event_type_e::ET_SELECTIVE_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN); + } + + void notify() { + EXPECT_TRUE(client_subscribed_); + EXPECT_TRUE(client_subscribed_selective_); + auto its_payload = vsomeip::runtime::get()->create_payload(); + + std::uint32_t i = 0; + + for (; i < notifications_to_send_; i++) { + its_payload->set_data(std::vector<vsomeip::byte_t>(i+1, 0x55)); + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + } + + for (; i < 2 * notifications_to_send_; i++) { + its_payload->set_data(std::vector<vsomeip::byte_t>(i+1, 0x55)); + app_->notify_one(service_info_.service_id, service_info_.instance_id, + service_info_.selective_event_id, its_payload, client_id_); + } + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_until_receive_messages_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "Service waiting for notify method has been called"; + while (wait_until_notify_method_called_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "Service notifying events"; + notify(); + + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + + its_lock.unlock(); + stop(); + } + + bool subscription_handler(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) { + (void)_uid; + (void)_gid; + VSOMEIP_DEBUG << __func__ << ": client 0x" << std::hex << std::setw(4) << std::setfill('0') << _client + << ((_subscribed) ? " subscribed" : "unsubscribed") << " on service."; + client_subscribed_ = _subscribed; + return true; + } + + bool selective_subscription_handler(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) { + (void)_uid; + (void)_gid; + VSOMEIP_DEBUG << __func__ << ": client 0x" << std::hex << std::setw(4) << std::setfill('0') << _client + << ((_subscribed) ? " subscribed" : "unsubscribed") << " on service."; + client_subscribed_selective_ = _subscribed; + client_id_ = _client; + return true; + } + +private: + struct second_address_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_ = true; + bool wait_until_receive_messages_ = true; + bool wait_until_notify_method_called_ = true; + bool wait_until_shutdown_method_called_ = true; + bool client_subscribed_ = false; + bool client_subscribed_selective_ = false; + vsomeip::client_t client_id_ = 0; + std::uint32_t messages_received_ = 0; + std::uint8_t notifications_to_send_ = 0; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; +}; + +TEST(someip_second_address_test, test_communication_with_client) +{ + second_address_test_service its_sample(second_address_test::service); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/CMakeLists.txt new file mode 100644 index 00000000000..fe3446291c9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(security_tests LANGUAGES CXX) + +if(TEST_SECURITY) + + # Configure necessary files into the build folder. + set(configuration_files + security_test_config_client_external_allow.json + security_test_config_client_external_deny.json + security_test_config_service_external_allow.json + security_test_config_service_external_deny.json + security_test_external_master_start.sh + security_test_external_slave_start.sh + security_test_local_config.json + security_test_local_start.sh + ) + configure_files("${configuration_files}") + + # Add test executable. + add_executable(security_test_service + security_test_service.cpp + ) + + # Add test executable. + add_executable(security_test_client + security_test_client.cpp + ) + + # Add build dependencies and link libraries to executables. + set(executables + security_test_service + security_test_client + ) + targets_add_default_dependencies("${executables}") + targets_link_default_libraries("${executables}") + + # Add custom test command. + add_custom_test( + NAME security_test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/security_test_local_start.sh + ) + + # Add custom test command. + add_custom_test( + NAME security_test_external_allow + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/security_test_external_master_start.sh security_test_config_client_external_allow.json --allow + ) + + # Add custom test command. + add_custom_test( + NAME security_test_external_deny + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/security_test_external_master_start.sh security_test_config_client_external_deny.json --deny + ) + +endif() diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_allow.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_allow.json.in new file mode 100644 index 00000000000..ab25fbbf0d9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_allow.json.in @@ -0,0 +1,90 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1255" + }, + { + "name" : "routingmanagerd", + "id" : "0x2222" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x111", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x1234", + "instance" : "0x02", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "security" : + { + "check_credentials" : "true", + "allow_remote_clients" : "true", + "policies" : + [ + { + "credentials" : { "uid" : "@TEST_UID@", "gid" : "@TEST_GID@" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : + [ + { + "ids" : ["0x5678"], + "methods" : [ {"first" : "0x8421", "last" : "0x8422" }, "0x8001", "0x7777" ] + } + ] + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "routing-credentials" : + { + "uid" : "@TEST_UID@", + "gid" : "@TEST_GID@" + }, + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_deny.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_deny.json.in new file mode 100644 index 00000000000..de5b6ab263c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_client_external_deny.json.in @@ -0,0 +1,90 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "client-sample", + "id" : "0x1255" + }, + { + "name" : "routingmanagerd", + "id" : "0x2222" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x111", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x1234", + "instance" : "0x02", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "security" : + { + "check_credentials" : "true", + "allow_remote_clients" : "false", + "policies" : + [ + { + "credentials" : { "uid" : "@TEST_UID@", "gid" : "@TEST_GID@" }, + "allow" : + { + "requests": + [ + { + "service" : "0x1234", + "instances" : + [ + { + "ids" : ["0x5678"], + "methods" : [ {"first" : "0x8421", "last" : "0x8422" }, "0x8001", "0x7777" ] + } + ] + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "routing-credentials" : + { + "uid" : "@TEST_UID@", + "gid" : "@TEST_GID@" + }, + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_allow.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_allow.json.in new file mode 100644 index 00000000000..25660b45b81 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_allow.json.in @@ -0,0 +1,84 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "routingmanagerd", + "id" : "0x1111" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x111", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x1234", + "instance" : "0x02", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "security" : + { + "check_credentials" : "true", + "allow_remote_clients" : "true", + "policies" : + [ + { + "credentials" : { "uid" : "@TEST_UID@", "gid" : "@TEST_GID@" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "routing-credentials" : + { + "uid" : "@TEST_UID@", + "gid" : "@TEST_GID@" + }, + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_deny.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_deny.json.in new file mode 100644 index 00000000000..97b398a6124 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_config_service_external_deny.json.in @@ -0,0 +1,84 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "routingmanagerd", + "id" : "0x1111" + } + ], + "services" : + [ + { + "service" : "0x1234", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x111", + "instance" : "0x5678", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + }, + { + "service" : "0x1234", + "instance" : "0x02", + "unicast" : "@TEST_IP_MASTER@", + "unreliable" : "30509" + } + ], + "security" : + { + "check_credentials" : "true", + "allow_remote_clients" : "false", + "policies" : + [ + { + "credentials" : { "uid" : "@TEST_UID@", "gid" : "@TEST_GID@" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "routing-credentials" : + { + "uid" : "@TEST_UID@", + "gid" : "@TEST_GID@" + }, + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_master_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_master_start.sh.in new file mode 100755 index 00000000000..1082bee3e19 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_master_start.sh.in @@ -0,0 +1,78 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ] +then + echo "Please pass a json file to this script and wether remote clients are allowed or not " + echo "For example: $0 security_test_config_client_external_allow.json --allow" + exit 1 +fi + +MASTER_JSON_FILE=$1 +SERVICE_JSON_FILE=${MASTER_JSON_FILE/client/service} +ALLOW_DENY=$2 + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=routingmanagerd +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=client-sample +./security_test_client --remote $2 & +PID_CLIENT=$! + + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting external security test on slave LXC" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/security_tests; ./security_test_external_slave_start.sh $SERVICE_JSON_FILE $2\"" & +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./security_test_external_slave_start.sh $SERVICE_JSON_FILE $2" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** security_test_external_slave_start.sh $SERVICE_JSON_FILE $2 +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** security_test_config_service_external_allow.json and +** security_test_config_client_external_allow.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for client_pid in "${PID_CLIENT}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_VSOMEIPD +kill $PID_CLIENT + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_slave_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_slave_start.sh.in new file mode 100755 index 00000000000..cff571410bd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_external_slave_start.sh.in @@ -0,0 +1,55 @@ +#!/bin/bash +# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ] +then + echo "Please pass a json file to this script and wether remote clients are allowed or not " + echo "For example: $0 security_test_config_service_external_allow.json --allow" + exit 1 +fi + +CLIENT_JSON_FILE=$1 +ALLOW_DENY=$2 + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=routingmanagerd +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +export VSOMEIP_CONFIGURATION=$1 +export VSOMEIP_APPLICATION_NAME=service-sample +./security_test_service --remote $2 & +PID_SERVICE=$! + +# Wait until client and service are finished +for client_pid in "${PID_SERVICE}" +do + if [ -n "$client_pid" ]; then + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait "$client_pid" || ((FAIL+=1)) + fi +done + +kill $PID_VSOMEIPD +kill $PID_SERVICE + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_config.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_config.json.in new file mode 100644 index 00000000000..51825c91087 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_config.json.in @@ -0,0 +1,78 @@ +{ + "unicast" : "localhost", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "service-sample", + "id" : "0x1277" + }, + { + "name" : "client-sample", + "id" : "0x1255" + }, + { + "name" : "routingmanagerd", + "id" : "0x1111" + } + ], + "security" : + { + "check_credentials" : "true", + "policies" : + [ + { + "credentials" : { "uid" : "@TEST_UID@", "gid" : "@TEST_GID@" }, + "allow" : + { + "offers": + [ + { + "service" : "0x1234", + "instance" : "0x5678" + } + ], + "requests": + [ + { + "service" : "0x1234", + "instances" : + [ + { + "ids" : ["0x5678"], + "methods" : [ {"first" : "0x8421", "last" : "0x8422" }, "0x8001", "0x7777" ] + } + ] + } + ] + } + } + ] + }, + "routing" : "routingmanagerd", + "routing-credentials" : + { + "uid" : "@TEST_UID@", + "gid" : "@TEST_GID@" + }, + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.244.224.245", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "100", + "repetitions_base_delay" : "200", + "repetitions_max" : "3", + "ttl" : "3", + "cyclic_offer_delay" : "2000", + "request_response_delay" : "1500" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_start.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_start.sh.in new file mode 100755 index 00000000000..d8ba2334724 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/conf/security_test_local_start.sh.in @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +export VSOMEIP_CONFIGURATION=security_test_local_config.json + +export VSOMEIP_APPLICATION_NAME=routingmanagerd +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +sleep 1 + +export VSOMEIP_APPLICATION_NAME=service-sample +./security_test_service --local & + +sleep 1 + +export VSOMEIP_APPLICATION_NAME=client-sample +./security_test_client --local + +kill $PID_VSOMEIPD +sleep 1 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.cpp new file mode 100644 index 00000000000..9c3c3dd6380 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.cpp @@ -0,0 +1,280 @@ +// Copyright (C) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "security_test_client.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; + +security_test_client::security_test_client(bool _test_external_communication, + bool _is_remote_client_allowed) + : app_(vsomeip::runtime::get()->create_application()), + is_available_(false), + sender_(std::bind(&security_test_client::run, this)), + received_responses_(0), + received_allowed_events_(0), + test_external_communication_(_test_external_communication), + is_remote_client_allowed_(_is_remote_client_allowed) { + +} + +bool security_test_client::init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind(&security_test_client::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&security_test_client::on_message, this, + std::placeholders::_1)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&security_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(0x111, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + std::bind(&security_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + 0x02, + std::bind(&security_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + return true; +} + +void security_test_client::start() { + VSOMEIP_INFO << "Starting..."; + + app_->start(); +} + +void security_test_client::stop() { + VSOMEIP_INFO << "Stopping..."; + + if (is_remote_client_allowed_) { + shutdown_service(); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + app_->clear_all_handler(); + app_->stop(); +} + +void security_test_client::on_state(vsomeip::state_type_e _state) { + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request not allowed service ID + app_->request_service(0x111, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, false); + + // request not allowed instance ID + app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, + 0x02, false); + + // request events of eventgroup 0x01 which holds events 0x8001 (allowed) and 0x8002 (denied) + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(0x01); + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), + its_eventgroups, vsomeip::event_type_e::ET_FIELD, + vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x01, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(0x8001)); + + app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x01, + vsomeip::DEFAULT_MAJOR, static_cast<vsomeip::event_t>(0x8002)); + } +} + +void security_test_client::on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + + VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client() + << " : Service [" << std::setw(4) << std::setfill('0') << std::hex + << _service << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + + // check that only the allowed service / instance ID gets available + if (_is_available) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _service); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _instance); + } + + if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service + && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) { + std::unique_lock<std::mutex> its_lock(mutex_); + if(is_available_ && !_is_available) { + is_available_ = false; + } + else if(_is_available && !is_available_) { + is_available_ = true; + condition_.notify_one(); + } + } +} + +void security_test_client::on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_service() + << "." + << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance() + << "] to Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() + << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() + << "]"; + + if(_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance()); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_METHOD_ID, _response->get_method()); + + if (_response->get_service() == vsomeip_test::TEST_SERVICE_SERVICE_ID && + _response->get_instance() == vsomeip_test::TEST_SERVICE_INSTANCE_ID && + _response->get_method() == vsomeip_test::TEST_SERVICE_METHOD_ID) { + received_responses_++; + if (received_responses_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS) { + VSOMEIP_WARNING << std::hex << app_->get_client() + << ": Received all messages ~> going down!"; + } + } + } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + // check that only allowed event 0x8001 is received + EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service()); + EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance()); + EXPECT_EQ(0x8001, _response->get_method()); + received_allowed_events_++; + } +} + +void security_test_client::run() { + for (uint32_t i = 0; i < vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS; ++i) { + { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!is_available_) + { + condition_.wait(its_lock); + } + } + + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID); + + // send a request which is allowed by policy -> expect answer + app_->send(request); + + // send a request with a not allowed method ID -> expect no answer + request->set_method(0x888); + app_->send(request); + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + if (!test_external_communication_) { + EXPECT_EQ(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS, + received_responses_); + EXPECT_EQ(received_allowed_events_, (uint32_t) 0x01); + } else if (test_external_communication_ && !is_remote_client_allowed_) { + EXPECT_EQ((uint32_t)0, received_responses_); + EXPECT_EQ((uint32_t)0, received_allowed_events_); + } else if (test_external_communication_ && is_remote_client_allowed_) { + EXPECT_EQ(vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS, + received_responses_); + EXPECT_EQ(received_allowed_events_, (uint32_t) 0x01); + } + stop(); +} + +void security_test_client::join_sender_thread() +{ + if (sender_.joinable()) { + sender_.join(); + } +} + +void security_test_client::shutdown_service() { + auto request = vsomeip::runtime::get()->create_request(false); + request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID); + request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID); + request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN); + app_->send(request); +} + +TEST(someip_security_test, basic_subscribe_request_response) +{ + security_test_client test_client(is_remote_test, remote_client_allowed); + if (test_client.init()) { + test_client.start(); + test_client.join_sender_thread(); + } +} + +int main(int argc, char** argv) { + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.hpp new file mode 100644 index 00000000000..ab3d98b8549 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_client.hpp @@ -0,0 +1,56 @@ + +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SECURITY_TEST_CLIENT_HPP +#define SECURITY_TEST_CLIENT_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> +#include <atomic> + +class security_test_client { +public: + security_test_client(bool _test_external_communication, + bool _is_remote_client_allowed); + bool init(); + void start(); + void stop(); + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr<vsomeip::message> &_response); + + void run(); + void join_sender_thread(); + +private: + void shutdown_service(); + + std::shared_ptr<vsomeip::application> app_; + + std::mutex mutex_; + std::condition_variable condition_; + bool is_available_; + + std::thread sender_; + + std::atomic<std::uint32_t> received_responses_; + std::atomic<std::uint32_t> received_allowed_events_; + + bool test_external_communication_; + bool is_remote_client_allowed_; +}; + +#endif // SECURITY_TEST_CLIENT_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.cpp new file mode 100644 index 00000000000..7843504b8c9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.cpp @@ -0,0 +1,219 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iomanip> + +#include "security_test_service.hpp" + +static bool is_remote_test = false; +static bool remote_client_allowed = true; + +security_test_service::security_test_service() : + app_(vsomeip::runtime::get()->create_application()), + is_registered_(false), + blocked_(false), + number_of_received_messages_(0), + offer_thread_(std::bind(&security_test_service::run, this)) { +} + +bool security_test_service::init() { + std::lock_guard<std::mutex> its_lock(mutex_); + + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip_test::TEST_SERVICE_METHOD_ID, + std::bind(&security_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID, + vsomeip_test::TEST_SERVICE_INSTANCE_ID, + vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN, + std::bind(&security_test_service::on_message_shutdown, this, + std::placeholders::_1)); + + app_->register_state_handler( + std::bind(&security_test_service::on_state, this, + std::placeholders::_1)); + + // offer allowed field 0x8001 eventgroup 0x01 + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(0x01); + + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // also offer field 0x8002 which is not allowed to be received by client + app_->offer_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + // set value to fields + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + vsomeip::byte_t its_data[2] = {static_cast<vsomeip::byte_t>((vsomeip_test::TEST_SERVICE_SERVICE_ID & 0xFF00) >> 8), + static_cast<vsomeip::byte_t>((vsomeip_test::TEST_SERVICE_SERVICE_ID & 0xFF))}; + its_payload->set_data(its_data, 2); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8001), its_payload); + + app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, + static_cast<vsomeip::event_t>(0x8002), its_payload); + + return true; +} + +void security_test_service::start() { + VSOMEIP_INFO << "Starting..."; + app_->start(); +} + +void security_test_service::stop() { + VSOMEIP_INFO << "Stopping..."; + app_->clear_all_handler(); + app_->stop(); +} + +void security_test_service::join_offer_thread() { + if (offer_thread_.joinable()) { + offer_thread_.join(); + } +} + +void security_test_service::offer() { + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); + + // try to offer a not allowed instance ID 0x02 (client requesting the service should not get available) + app_->offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, 0x02); + + // try to offer a not allowed service ID 0x111 (client requesting the service should not get available) + app_->offer_service(0x111, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void security_test_service::stop_offer() { + app_->stop_offer_service(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID); +} + +void security_test_service::on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." : + "deregistered."); + + if(_state == vsomeip::state_type_e::ST_REGISTERED) { + if(!is_registered_) { + is_registered_ = true; + std::lock_guard<std::mutex> its_lock(mutex_); + blocked_ = true; + // "start" the run method thread + condition_.notify_one(); + } + } + else { + is_registered_ = false; + } +} + +void security_test_service::on_message(const std::shared_ptr<vsomeip::message>& _request) { + ASSERT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _request->get_service()); + ASSERT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _request->get_instance()); + + VSOMEIP_INFO << "Received a message with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _request->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _request->get_session() << "] method: " << _request->get_method() ; + + // send response + std::shared_ptr<vsomeip::message> its_response = + vsomeip::runtime::get()->create_response(_request); + + app_->send(its_response); + + number_of_received_messages_++; + if(number_of_received_messages_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS) { + VSOMEIP_INFO << "Received all messages!"; + } +} + +void security_test_service::on_message_shutdown( + const std::shared_ptr<vsomeip::message>& _request) { + (void)_request; + VSOMEIP_INFO << "Shutdown method was called, going down now."; + stop(); +} + +void security_test_service::run() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (!blocked_) + condition_.wait(its_lock); + + offer(); + + // do not wait for the shutdown method to be called + if (is_remote_test && !remote_client_allowed) { + std::this_thread::sleep_for(std::chrono::milliseconds(250 * vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS + 10000)); + VSOMEIP_INFO << "Shutdown the service after timeout as remote client is not allowed by policy to call shutdown method!"; + stop(); + } + +} + +TEST(someip_security_test, basic_subscribe_request_response) { + security_test_service test_service; + if (test_service.init()) { + test_service.start(); + test_service.join_offer_thread(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + std::string test_remote("--remote"); + std::string test_local("--local"); + std::string test_allow_remote_client("--allow"); + std::string test_deny_remote_client("--deny"); + std::string help("--help"); + + int i = 1; + while (i < argc) + { + if(test_remote == argv[i]) + { + is_remote_test = true; + } + else if(test_local == argv[i]) + { + is_remote_test = false; + } + else if(test_allow_remote_client == argv[i]) + { + remote_client_allowed = true; + } + else if(test_deny_remote_client == argv[i]) + { + remote_client_allowed = false; + } + else if(help == argv[i]) + { + VSOMEIP_INFO << "Parameters:\n" + << "--remote: Run test between two hosts\n" + << "--local: Run test locally\n" + << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n" + << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n" + << "--help: print this help"; + } + i++; + } + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.hpp new file mode 100644 index 00000000000..87fb94fdf01 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/security_tests/security_test_service.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SECURITY_TEST_SERVICE_HPP +#define SECURITY_TEST_SERVICE_HPP + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#include <thread> +#include <mutex> +#include <condition_variable> + +class security_test_service { +public: + security_test_service(); + bool init(); + void start(); + void stop(); + void offer(); + void stop_offer(); + void join_offer_thread(); + void on_state(vsomeip::state_type_e _state); + void on_message(const std::shared_ptr<vsomeip::message> &_request); + void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request); + void run(); + +private: + std::shared_ptr<vsomeip::application> app_; + bool is_registered_; + + std::mutex mutex_; + std::condition_variable condition_; + bool blocked_; + std::uint32_t number_of_received_messages_; + std::thread offer_thread_; +}; + +#endif // SECURITY_TEST_SERVICE_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_test_globals.hpp new file mode 100644 index 00000000000..adaf6849f9a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_test_globals.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SOMEIP_TEST_GLOBALS_HPP_ +#define SOMEIP_TEST_GLOBALS_HPP_ + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#ifdef USE_DLT +#ifndef ANDROID +#include <dlt/dlt.h> +#endif +#endif + +namespace vsomeip_test +{ + +// Service +constexpr vsomeip::service_t TEST_SERVICE_SERVICE_ID = 0x1234; +constexpr vsomeip::instance_t TEST_SERVICE_INSTANCE_ID = 0x5678; +constexpr vsomeip::method_t TEST_SERVICE_METHOD_ID = 0x8421; +constexpr vsomeip::method_t TEST_SERVICE_METHOD_ID_SHUTDOWN = 0x7777; +constexpr vsomeip::method_t TEST_SERVICE_DETACH_METHOD_ID_LOOP_LONG = 0x8887; +constexpr vsomeip::method_t TEST_SERVICE_DETACH_METHOD_ID_LOOP_SHORT = 0x8888; +constexpr vsomeip::method_t TEST_SERVICE_DETACH_METHOD_ID = 0x8889; +constexpr vsomeip::client_t TEST_SERVICE_CLIENT_ID = 0x1277; + +// Client local +constexpr vsomeip::client_t TEST_CLIENT_CLIENT_ID = 0x1255; + +// Client external +constexpr vsomeip::client_t TEST_CLIENT_EXTERNAL_CLIENT_ID = 0x1644; + + +constexpr std::uint32_t NUMBER_OF_MESSAGES_TO_SEND = 10; +constexpr vsomeip::session_t TEST_INITIAL_SESSION_ID = 0x1; + +constexpr std::uint32_t NUMBER_OF_MESSAGES_TO_SEND_PAYLOAD_TESTS = 1000; +constexpr vsomeip::byte_t PAYLOAD_TEST_DATA = 0xDD; +constexpr std::uint32_t MAX_PAYLOADSIZE = 1024*128; +// TR_SOMEIP_00061 +constexpr std::uint32_t MAX_PAYLOADSIZE_UDP = 1400; + +constexpr std::uint32_t NUMBER_OF_MESSAGES_TO_SEND_ROUTING_RESTART_TESTS = 32; + +constexpr std::uint32_t NUMBER_OF_MESSAGES_TO_SEND_SECURITY_TESTS = 32; + +constexpr std::uint32_t NUMBER_OF_CLIENTS_TO_REQUEST_SHUTDOWN = 4; +} + +#endif /* SOMEIP_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/CMakeLists.txt new file mode 100644 index 00000000000..53d72f7ee90 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/CMakeLists.txt @@ -0,0 +1,109 @@ +# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(someip_tp_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + someip_tp_test_master.json + someip_tp_test_master_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(someip_tp_test_service + someip_tp_test_service.cpp +) + +# Add test executable. +set(service_discovery_sources + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/configuration_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/entry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/eventgroupentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ip_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv4_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/ipv6_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/load_balancing_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_element_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/protection_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/selective_option_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/serviceentry_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/service_discovery/src/unknown_option_impl.cpp +) +set(message_sources + ${CMAKE_SOURCE_DIR}/implementation/message/src/deserializer.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/message_impl.cpp + ${CMAKE_SOURCE_DIR}/implementation/message/src/payload_impl.cpp +) +set(endpoint_sources + ${CMAKE_SOURCE_DIR}/implementation/endpoints/src/tp.cpp + ${CMAKE_SOURCE_DIR}/implementation/endpoints/src/tp_reassembler.cpp + ${CMAKE_SOURCE_DIR}/implementation/endpoints/src/tp_message.cpp +) +add_executable(someip_tp_test_msg_sender + someip_tp_test_msg_sender.cpp + ${service_discovery_sources} + ${message_sources} + ${endpoint_sources} +) + +# Link vsomeip-sd to test executable. +target_link_libraries(someip_tp_test_msg_sender + ${VSOMEIP_NAME}-sd +) + +# Add build dependencies and link libraries to executables. +set(executables + someip_tp_test_service + someip_tp_test_msg_sender +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_in_sequence + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh IN_SEQUENCE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_mixed + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh MIXED + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_incomplete + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh INCOMPLETE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_duplicate + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh DUPLICATE + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_overlap + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh OVERLAP + TIMEOUT 180 +) + +# Add custom test command. +add_custom_test( + NAME someip_tp_test_overlap_front_back + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/someip_tp_test_master_starter.sh OVERLAP_FRONT_BACK + TIMEOUT 180 +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in new file mode 100644 index 00000000000..b3f9ee43636 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in @@ -0,0 +1,44 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"info", + "console":"true" + }, + "applications" : + [ + { + "name" : "someip_tp_test_service", + "id" : "0xCAFE" + } + ], + "services": + [ + { + "service":"0x4545", + "instance":"0x1", + "unreliable":"30001", + "someip-tp" : { + "service-to-client": [ "0x4545", "0x8001"] + } + }, + { + "service":"0x6767", + "instance":"0x1", + "unreliable":"40001", + "someip-tp" : { + "client-to-service": [ "0x6767", "0x8001" ] + } + } + ], + "max-payload-size-unreliable" : "8352", + "routing":"routingmanagerd", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.77.1", + "port":"30490", + "protocol":"udp", + "cyclic_offer_delay" : "1000" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in new file mode 100755 index 00000000000..46e3ced4e45 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in @@ -0,0 +1,65 @@ +#!/bin/bash +# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +if [ $# -lt 1 ] +then + echo "Please pass a test mode to this script." + echo "For example: $0 IN_SEQUENCE" + echo "Valid subscription types include:" + echo " [IN_SEQUENCE, MIXED, INCOMPLETE, DUPLICATE, OVERLAP, OVERLAP_FRONT_BACK]" + exit 1 +fi +TESTMODE=$1 +export VSOMEIP_CONFIGURATION=someip_tp_test_master.json +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! +# Start the services +./someip_tp_test_service $1 & +PID_SERIVCE=$! + +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "Waiting for 5s" + sleep 5 + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/someip_tp_tests; ./someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE\"" & + echo "remote ssh pid: $!" +elif [ ! -z "$USE_DOCKER" ]; then + echo "Waiting for 5s" + sleep 5 + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE" & +else +cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** someip_tp_test_master.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until all clients and services are finished +for job in $PID_SERIVCE +do + # Fail gets incremented if a client exits with a non-zero exit code + echo "waiting for $job" + wait $job || FAIL=$(($FAIL+1)) +done + +# kill the services +kill $PID_VSOMEIPD +sleep 1 + +# Check if everything went well +exit $FAIL diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp new file mode 100644 index 00000000000..723cfe1d6f0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SOMEIP_TP_TEST_GLOBALS_HPP_ +#define SOMEIP_TP_TEST_GLOBALS_HPP_ + +#include <vsomeip/primitive_types.hpp> + +namespace someip_tp_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; + vsomeip::method_t shutdown_method_id; + vsomeip::method_t notify_method_id; +}; + +struct service_info service = { 0x4545, 0x1, 0x4545, 0x8001, 0x1, 0x4501, 0x4502 }; +struct service_info service_slave = { 0x6767, 0x1, 0x6767, 0x8001, 0x1, 0x6701, 0x6702 }; + +enum test_mode_e { + IN_SEQUENCE, + MIXED, + INCOMPLETE, + DUPLICATE, + OVERLAP, + OVERLAP_FRONT_BACK +}; + +const std::uint32_t number_of_fragments = 6; +const std::uint32_t max_segment_size = 1392; + +} + +#endif /* SOMEIP_TP_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp new file mode 100644 index 00000000000..f097f43c298 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp @@ -0,0 +1,1368 @@ +// Copyright (C) 2015-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <iostream> +#include <memory> +#include <thread> +#include <chrono> +#include <cstring> +#include <future> +#include <numeric> +#include <random> +#include <algorithm> +#include <list> + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +#include <arpa/inet.h> +#endif + +#include <gtest/gtest.h> + +#include <boost/asio.hpp> + +#include <vsomeip/vsomeip.hpp> + +#include "../../implementation/utility/include/bithelper.hpp" +#include "../../implementation/message/include/deserializer.hpp" +#include "../../implementation/message/include/serializer.hpp" +#include "../../implementation/service_discovery/include/service_discovery.hpp" +#include "../../implementation/service_discovery/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/constants.hpp" +#include "../../implementation/service_discovery/include/enumeration_types.hpp" +#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp" +#include "../../implementation/service_discovery/include/serviceentry_impl.hpp" +#include "../../implementation/message/include/message_impl.hpp" +#include "../../implementation/service_discovery/include/option_impl.hpp" +#include "../../implementation/service_discovery/include/ipv4_option_impl.hpp" +#include "../../implementation/endpoints/include/tp.hpp" +#include "../../implementation/endpoints/include/tp_reassembler.hpp" +#include "../../implementation/message/include/payload_impl.hpp" + +#include "someip_tp_test_globals.hpp" + +static char* remote_address; +static char* local_address; + +std::vector<someip_tp_test::test_mode_e> its_modes({ + someip_tp_test::test_mode_e::IN_SEQUENCE, + someip_tp_test::test_mode_e::MIXED, + someip_tp_test::test_mode_e::INCOMPLETE, + someip_tp_test::test_mode_e::DUPLICATE, + someip_tp_test::test_mode_e::OVERLAP, + someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK, +}); + +class someip_tp : public ::testing::TestWithParam<someip_tp_test::test_mode_e> { +public: + someip_tp() : + work_(std::make_shared<boost::asio::io_context::work>(io_)), + io_thread_(std::bind(&someip_tp::io_run, this)), + session_(0x0), + sd_session_(0x0), + address_remote_(boost::asio::ip::address::from_string(std::string(remote_address))), + address_local_(boost::asio::ip::address::from_string(std::string(local_address))), + runtime_(vsomeip::runtime::get()) {} +protected: + void TearDown() { + work_.reset(); + io_thread_.join(); + io_.stop(); + } + + void call_shutdown_method() { + boost::system::error_code ec; + std::uint8_t shutdown_call[] = { + 0x45, 0x45, 0x45, 0x01, + 0x00, 0x00, 0x00, 0x08, + 0xDD, 0xDD, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00 }; + boost::asio::ip::udp::socket::endpoint_type target_service(address_remote_, + 30001); + boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4()); + udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service); + udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_socket2.close(ec); + } + + void io_run() { + io_.run(); + } + + void offer_service(boost::asio::ip::udp::socket* const _udp_socket) { + // offer the service + std::uint8_t its_offer_service_message[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x01, 0x00, 0x00, 0x20, + 0x67, 0x67, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x00, // minor + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x11, 0x9c, 0x41, + }; + std::memcpy(&its_offer_service_message[48], &address_local_.to_v4().to_bytes()[0], 4); + std::uint16_t its_session = htons(++sd_session_); + std::memcpy(&its_offer_service_message[10], &its_session, sizeof(its_session)); + + boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490); + _udp_socket->send_to(boost::asio::buffer(its_offer_service_message), target_sd); + } + + void subscribe_at_master(boost::asio::ip::udp::socket* const _udp_socket) { + std::uint8_t its_subscription[] = { + 0xff, 0xff, 0x81, 0x00, + 0x00, 0x00, 0x00, 0x30, // length + 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x00, + 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, // length entries array + 0x06, 0x00, 0x00, 0x10, + 0x45, 0x45, 0x00, 0x01, // service / instance + 0x00, 0xff, 0xff, 0xff, // major / ttl + 0x00, 0x00, 0x00, 0x01, // counter + 0x00, 0x00, 0x00, 0x0c, // length options array + 0x00, 0x09, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, // slave address + 0x00, 0x11, 0x75, 0x31, // port 30001 + }; + std::memcpy(&its_subscription[48], &address_local_.to_v4().to_bytes()[0], 4); + std::uint16_t its_session = htons(++sd_session_); + std::memcpy(&its_subscription[10], &its_session, sizeof(its_session)); + + boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490); + _udp_socket->send_to(boost::asio::buffer(its_subscription), target_sd); + } + + /* + * @brief custom version of tp::tp_split_message with adjustable segment size + * needed to send overlapping segments within the 1392 byte segment size limit + */ + vsomeip::tp::tp_split_messages_t split_message(const std::uint8_t * const _data, + std::uint32_t _size , std::uint32_t _segment_size) { + using namespace vsomeip::tp; + using namespace vsomeip; + tp_split_messages_t split_messages; + + if (_size < VSOMEIP_MAX_UDP_MESSAGE_SIZE) { + std::cerr << __func__ << " called with size: " << std::dec << _size; + return split_messages; + } + + const auto data_end = _data + _size; + + for (auto current_offset = _data + 16; current_offset < data_end;) { + auto msg = std::make_shared<message_buffer_t>(); + msg->reserve(VSOMEIP_FULL_HEADER_SIZE + sizeof(tp_header_t) + _segment_size); + // copy the header + msg->insert(msg->end(), _data, _data + VSOMEIP_FULL_HEADER_SIZE); + // change the message type + (*msg)[VSOMEIP_MESSAGE_TYPE_POS] = (*msg)[VSOMEIP_MESSAGE_TYPE_POS] | 0x20; + // check if last segment + const auto segment_end = current_offset + _segment_size; + const bool is_last_segment = (segment_end >= data_end); + // insert tp_header + const tp_header_t header = htonl( + static_cast<tp_header_t>((current_offset - VSOMEIP_FULL_HEADER_SIZE - _data)) | + static_cast<tp_header_t>((is_last_segment) ? 0x0u : 0x1u)); + + const byte_t * const headerp = reinterpret_cast<const byte_t*>(&header); + msg->insert(msg->end(), headerp, headerp + sizeof(tp_header_t)); + + // insert payload + if (is_last_segment) { + msg->insert(msg->end(), current_offset, data_end); + current_offset = data_end; + } else { + msg->insert(msg->end(), current_offset, segment_end); + current_offset += _segment_size; + } + // update length + const length_t its_length = static_cast<length_t>(msg->size() + - VSOMEIP_SOMEIP_HEADER_SIZE); + *(reinterpret_cast<length_t*>(&(*msg)[VSOMEIP_LENGTH_POS_MIN])) = htonl(its_length); + split_messages.emplace_back(std::move(msg)); + } + + return split_messages; + } + + void create_fragments(std::uint32_t _count, vsomeip::service_t _service, + vsomeip::instance_t _instance, + vsomeip::method_t _method, + vsomeip::message_type_e _message_type, + vsomeip::client_t _client, + vsomeip::session_t _session, + std::vector<vsomeip::message_buffer_ptr_t>* _target, + std::uint32_t _segment_size) { + vsomeip::message_impl msg; + msg.set_reliable(false); + msg.set_service(_service); + msg.set_instance(_instance); + msg.set_method(_method); + msg.set_message_type(_message_type); + msg.set_return_code(vsomeip::return_code_e::E_OK); + if (_client == vsomeip::ANY_CLIENT) { + msg.set_client(0xDDDD); + } else { + msg.set_client(_client); + } + if (_session == 0xFFFF) { + msg.set_session(++session_); + } else { + msg.set_session(_session); + } + std::vector<vsomeip::byte_t> its_payload_data; + for (uint32_t i = 0; i < _count; i++) { + its_payload_data.resize((i * _segment_size) + _segment_size, static_cast<std::uint8_t>(i)); + } + std::shared_ptr<vsomeip::payload> payload = std::make_shared<vsomeip::payload_impl>(its_payload_data); + msg.set_payload(payload); + vsomeip::serializer its_serializer(0); + msg.serialize(&its_serializer); + + *_target = split_message(its_serializer.get_data(), its_serializer.get_size(), _segment_size); + its_serializer.reset(); + + } + + vsomeip::message_buffer_t create_full_message( + const std::vector<vsomeip::message_buffer_ptr_t>& _fragments) { + auto its_reassembler = std::make_shared<vsomeip::tp::tp_reassembler>( + std::numeric_limits<std::uint32_t>::max(), io_); + vsomeip::message_buffer_t its_reassemlbed_msg; + for (const auto& frag : _fragments) { + const auto res = its_reassembler->process_tp_message(&(*frag)[0], + std::uint32_t(frag->size()), address_local_, 12345); + if (res.first) { + its_reassemlbed_msg = res.second; + } + } + its_reassembler->stop(); + return its_reassemlbed_msg; + } + + std::vector<int> create_shuffled_seqeuence(std::uint32_t _count) { + std::vector<int> its_indexes(_count); + std::iota(its_indexes.begin(), its_indexes.end(), 0); + std::random_device rd; + std::mt19937 its_twister(rd()); + std::shuffle(its_indexes.begin(), its_indexes.end(), its_twister); + return its_indexes; + } + void increase_segment_back(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + _seg->resize(_seg->size() + _amount, 0xff); + // update length + *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) = + htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE)); + } + + void increase_segment_front(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + // increase segment by amount + _seg->insert(_seg->begin() + VSOMEIP_TP_PAYLOAD_POS, _amount, 0xff); + + // decrease offset by amount + const vsomeip::tp::tp_header_t its_tp_header = vsomeip::bithelper::read_uint32_be(&(*_seg)[VSOMEIP_TP_HEADER_POS_MIN]); + std::uint32_t its_offset = vsomeip::tp::tp::get_offset(its_tp_header); + its_offset -= _amount; + const vsomeip::tp::tp_header_t its_new_tp_header = + htonl(static_cast<vsomeip::tp::tp_header_t>(its_offset | + static_cast<vsomeip::tp::tp_header_t>(its_tp_header & 0x1))); + *(reinterpret_cast<vsomeip::tp::tp_header_t*>( + &((*_seg)[VSOMEIP_TP_HEADER_POS_MIN]))) = its_new_tp_header; + + // update length + *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) = + htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE)); + } + + void increase_segment_front_back(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + increase_segment_front(_seg, _amount); + increase_segment_back(_seg, _amount); + } + + void decrease_segment_back(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + _seg->resize(_seg->size() - _amount, 0xff); + // update length + *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) = + htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE)); + } + + void decrease_segment_front(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + if (_amount % 16 != 0) { + std::cerr << __func__ << ":" << __LINE__ << std::endl; + return; + } + _seg->erase(_seg->begin() + VSOMEIP_TP_PAYLOAD_POS, _seg->begin() + VSOMEIP_TP_PAYLOAD_POS + _amount); + // increase offset by amount + const vsomeip::tp::tp_header_t its_tp_header = vsomeip::bithelper::read_uint32_be(&(*_seg)[VSOMEIP_TP_HEADER_POS_MIN]); + std::uint32_t its_offset = vsomeip::tp::tp::get_offset(its_tp_header); + its_offset += _amount; + const vsomeip::tp::tp_header_t its_new_tp_header = + htonl(static_cast<vsomeip::tp::tp_header_t>(its_offset | + static_cast<vsomeip::tp::tp_header_t>(its_tp_header & 0x1))); + *(reinterpret_cast<vsomeip::tp::tp_header_t*>( + &((*_seg)[VSOMEIP_TP_HEADER_POS_MIN]))) = its_new_tp_header; + // update length + *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) = + htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE)); + } + + void decrease_segment_front_back(const vsomeip::message_buffer_ptr_t& _seg, + std::uint32_t _amount) { + if (_amount % 16 != 0) { + std::cerr << __func__ << ":" << __LINE__ << std::endl; + return; + } + decrease_segment_back(_seg, _amount); + decrease_segment_front(_seg, _amount); + } + + + enum order_e { + ASCENDING, + DESCENDING, + MIXED_PREDEFINED, + MIXED_RANDOM, + }; + + boost::asio::io_context io_; + std::shared_ptr<boost::asio::io_context::work> work_; + std::thread io_thread_; + std::vector<vsomeip::message_buffer_ptr_t> fragments_request_to_master_; + std::vector<vsomeip::message_buffer_ptr_t> fragments_response_of_master_; + + std::vector<vsomeip::message_buffer_ptr_t> fragments_received_as_server_; + std::vector<vsomeip::message_buffer_ptr_t> fragments_response_to_master_; + + std::vector<vsomeip::message_buffer_ptr_t> fragments_event_from_master_; + std::vector<vsomeip::message_buffer_ptr_t> fragments_event_to_master_; + + std::atomic<std::uint16_t> session_; + std::atomic<std::uint16_t> sd_session_; + boost::asio::ip::address address_remote_; + boost::asio::ip::address address_local_; + std::shared_ptr<vsomeip::runtime> runtime_; + someip_tp_test::test_mode_e test_mode_ = GetParam(); +}; + +INSTANTIATE_TEST_CASE_P(send_in_mode, + someip_tp, + ::testing::ValuesIn(its_modes)); + + +/* + * @test Send a big fragmented UDP request to the master and wait for the + * response. Check that the received response is the same as the request (server + * just echos the requests). + * Wait for a big fragmented UDP message request from the master and send back + * the response in the same size. Check that the request and response are + * identical. + * Do this two times one with fragments ordered ascending and one time descending. + * Wait for the master to subscribe and send back two big, fragmented + * notifications one with fragments ordered ascending and one descending + * Subscribe at master and wait for one fragmented event. + * With testmode INCOMPLETE incomplete fragments are send as well + * With testmode MIXED instead of ascending/descedning order the fragments are + * send in a predefined or in a random order + */ +TEST_P(someip_tp, send_in_mode) +{ + std::promise<void> remote_client_subscribed; + std::atomic<std::uint16_t> remote_client_subscription_port(0); + std::promise<void> offer_received; + + std::mutex udp_sd_socket_mutex; + boost::asio::ip::udp::socket udp_sd_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490)); + + boost::asio::ip::udp::socket udp_client_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30001)); + + boost::asio::ip::udp::socket udp_server_socket(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 40001)); + + std::thread sd_receive_thread([&](){ + std::atomic<bool> keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + std::vector<vsomeip::event_t> its_received_events; + std::atomic<bool> service_offered(false); + std::atomic<bool> client_subscribed(false); + + // join the sd multicast group 224.0.77.1 + udp_sd_socket.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string("224.0.77.1").to_v4())); + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_sd_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[VSOMEIP_METHOD_POS_MIN]); + + if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) { + vsomeip::sd::message_impl sd_msg; + EXPECT_TRUE(sd_msg.deserialize(&its_deserializer)); + EXPECT_EQ(1u, sd_msg.get_entries().size()); + for (const auto& e : sd_msg.get_entries()) { + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) { + EXPECT_TRUE(e->is_eventgroup_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type()); + EXPECT_EQ(1,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(someip_tp_test::service_slave.service_id, e->get_service()); + EXPECT_EQ(someip_tp_test::service_slave.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) { + std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e); + EXPECT_EQ(someip_tp_test::service_slave.eventgroup_id, + its_casted_entry->get_eventgroup()); + std::shared_ptr<vsomeip::sd::option_impl> its_option = + sd_msg.get_options().at(its_casted_entry->get_options(1)[0]); + EXPECT_TRUE(its_option > 0); + if(its_option->get_type() == vsomeip::sd::option_type_e::IP4_ENDPOINT) { + std::shared_ptr<vsomeip::sd::ipv4_option_impl> its_ipv4_option = + std::dynamic_pointer_cast<vsomeip::sd::ipv4_option_impl> (its_option); + EXPECT_TRUE(its_ipv4_option > 0); + EXPECT_EQ(vsomeip::sd::layer_four_protocol_e::UDP, its_ipv4_option->get_layer_four_protocol()); + EXPECT_EQ(address_remote_, + boost::asio::ip::address( + boost::asio::ip::address_v4(its_ipv4_option->get_address()))); + remote_client_subscription_port = its_ipv4_option->get_port(); + } + std::vector<vsomeip::byte_t> its_sub_ack(&receive_buffer[0], &receive_buffer[0] + VSOMEIP_FULL_HEADER_SIZE + 8 + (sd_msg.get_entries().size() * 16)); + its_sub_ack[24] = static_cast<vsomeip::byte_t>(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK); + // fix length + const std::uint32_t its_length = htonl(static_cast<std::uint32_t>(its_sub_ack.size()) - VSOMEIP_SOMEIP_HEADER_SIZE); + std::memcpy(&its_sub_ack[4], &its_length, sizeof(its_length)); + // set number of options to zero + its_sub_ack[27] = 0x0; + // update session + std::uint16_t its_session = htons(++sd_session_); + std::memcpy(&its_sub_ack[10], &its_session, sizeof(its_session)); + boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490); + { + std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex); + udp_sd_socket.send_to(boost::asio::buffer(its_sub_ack), target_sd); + } + std::cout << __LINE__ << ": master subscribed" << std::endl; + remote_client_subscribed.set_value(); + client_subscribed = true; + } + } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) { + EXPECT_TRUE(e->is_service_entry()); + EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type()); + EXPECT_EQ(1u,e->get_num_options(1)); + EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl()); + EXPECT_EQ(someip_tp_test::service.service_id, e->get_service()); + EXPECT_EQ(someip_tp_test::service.instance_id, e->get_instance()); + EXPECT_EQ(1u, sd_msg.get_options().size()); + if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) { + std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry = + std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e); + EXPECT_EQ(0u, its_casted_entry->get_minor_version()); + } + offer_received.set_value(); + service_offered = true; + } + } + if (service_offered && client_subscribed) { + keep_receiving = false; + } + } else { + ADD_FAILURE() << " received non-sd message"; + return; + } + } + } + }); + + std::thread send_thread([&]() { + boost::system::error_code ec; + try { + + // wait until a offer was received + if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Didn't receive offer within time"; + return; + } + + { + std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex); + subscribe_at_master(&udp_sd_socket); + } + + std::mutex all_fragments_received_mutex_; + std::condition_variable all_fragments_received_cond_; + bool wait_for_all_response_fragments_received_(true); + std::uint32_t received_responses(0); + bool wait_for_all_event_fragments_received_(true); + + std::thread udp_client_receive_thread([&]() { + bool keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + while (keep_receiving) { + boost::system::error_code error; + std::size_t bytes_transferred = udp_client_socket.receive( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + std::uint32_t its_pos = 0; + + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be( + &receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + std::cout << __LINE__ << ": received response " << its_message_size << std::endl; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type()); + EXPECT_EQ(someip_tp_test::service.service_id, msg.get_service()); + } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + std::cout << __LINE__ << ": received event" << std::endl; + } else if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) && + vsomeip::tp::tp::tp_flag_unset(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) == vsomeip::message_type_e::MT_RESPONSE) { + EXPECT_EQ(someip_tp_test::service.service_id, its_service); + EXPECT_EQ(someip_tp_test::service.method_id, its_method); + auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size); + + fragments_response_of_master_.push_back(its_buffer); + if (fragments_response_of_master_.size() == someip_tp_test::number_of_fragments) { + std::lock_guard<std::mutex> its_lock(all_fragments_received_mutex_); + wait_for_all_response_fragments_received_ = false; + std::cout << __LINE__ << ": received all response fragments as client" << std::endl; + all_fragments_received_cond_.notify_one(); + if (++received_responses == 2 && !wait_for_all_event_fragments_received_) { + std::cout << __LINE__ << ": received all responses as client --> Finished" << std::endl; + keep_receiving = false; + } + } + } else if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) && + vsomeip::tp::tp::tp_flag_unset(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) == vsomeip::message_type_e::MT_NOTIFICATION) { + std::cout << __LINE__ << ": received event fragment" << std::endl; + EXPECT_EQ(someip_tp_test::service.service_id, its_service); + EXPECT_EQ(someip_tp_test::service.event_id, its_method); + auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size); + fragments_event_from_master_.push_back(its_buffer); + if (fragments_event_from_master_.size() == someip_tp_test::number_of_fragments) { + std::lock_guard<std::mutex> its_lock(all_fragments_received_mutex_); + wait_for_all_event_fragments_received_ = false; + std::cout << __LINE__ << ": received all event fragments as client --> Finished" << std::endl; + all_fragments_received_cond_.notify_one(); + if (received_responses == 2) { + keep_receiving = false; + } + } + + } + its_pos += its_message_size; + bytes_transferred -= its_message_size; + } + } + } + }); + + // send SOMEI-TP message fragmented into 6 parts to service: + boost::asio::ip::udp::socket::endpoint_type target_service(address_remote_, 30001); + + std::unique_lock<std::mutex> its_lock(all_fragments_received_mutex_); + for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) { + create_fragments(someip_tp_test::number_of_fragments, someip_tp_test::service.service_id, + someip_tp_test::service.instance_id, + someip_tp_test::service.method_id, + vsomeip::message_type_e::MT_REQUEST, + vsomeip::ANY_CLIENT, 0xffff, + &fragments_request_to_master_, + (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ? + vsomeip::tp::tp::tp_max_segment_length_ - 160 : + vsomeip::tp::tp::tp_max_segment_length_); + if (mode == order_e::ASCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } else { + auto its_indexes = {4, 1, 3, 5, 2, 0}; + std::cout << __LINE__ << ": using following predefined sequence to send request to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for (int i : its_indexes) { + udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {0,1,3,5,2,4}; + std::cout << __LINE__ << ": using following predefined sequence to send request to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase third segment by 16 byte at front and back + increase_segment_front_back(fragments_request_to_master_[2], 16); + increase_segment_front(fragments_request_to_master_[4], 16); + for (int i : its_indexes) { + udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_request_to_master_.begin(); + iter != fragments_request_to_master_.end(); iter++) { + udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service); + // send insert 2nd fragment twice + if (iter == fragments_request_to_master_.begin() + 1) { + udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 3) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send a request fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_request_to_master_[2]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x33; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x33; + udp_client_socket.send_to(boost::asio::buffer(msg_incomplete), target_service); + // send a request from a different src port as well to test cleanup + boost::asio::ip::udp::socket udp_client_socket2(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30004)); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xcc; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xcc; + udp_client_socket2.send_to(boost::asio::buffer(msg_incomplete), target_service); + boost::system::error_code ec; + udp_client_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_client_socket2.close(ec); + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + increase_segment_back(fragments_request_to_master_[1], 16); + } + for (const auto& fragment : fragments_request_to_master_) { + udp_client_socket.send_to(boost::asio::buffer(*fragment), target_service); + } + } + } else if (mode == order_e::DESCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments); + std::cout << __LINE__ << ": using following random sequence to send request to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for (int i : its_indexes) { + udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service); + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {5,3,2,4,1,0}; + std::cout << __LINE__ << ": using following predefined sequence to send request to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase third segment by 16 byte at front and back + increase_segment_front_back(fragments_request_to_master_[4], 16); + for (int i : its_indexes) { + udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_request_to_master_.rbegin(); + iter != fragments_request_to_master_.rend(); iter++) { + udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service); + // send insert 2nd last fragment twice + if (iter == fragments_request_to_master_.rbegin() + 1) { + udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 4) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send a request fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_request_to_master_[3]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x77; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x77; + udp_client_socket.send_to(boost::asio::buffer(msg_incomplete), target_service); + + // send a request from a different src port as well to test cleanup + boost::asio::ip::udp::socket udp_client_socket2(io_, + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30005)); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xdd; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xdd; + udp_client_socket2.send_to(boost::asio::buffer(msg_incomplete), target_service); + boost::system::error_code ec; + udp_client_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_client_socket2.close(ec); + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 5) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // increase second last segment by 16 byte + increase_segment_back(fragments_request_to_master_[4], 16); + } + for (auto iter = fragments_request_to_master_.rbegin(); iter != fragments_request_to_master_.rend(); iter++) { + udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service); + } + } + } + { + while (wait_for_all_response_fragments_received_) { + if (std::cv_status::timeout == + all_fragments_received_cond_.wait_for(its_lock, + std::chrono::seconds(20))) { + ADD_FAILURE() << "Didn't receive response to" + " fragmented message within time: " << std::uint32_t(mode); + return; + } else { + EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_request_to_master_.size()); + // create complete message from request + if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (mode == ASCENDING) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // decrease second segment by 16 byte + decrease_segment_back(fragments_request_to_master_[1], 16); + } else if (mode == DESCENDING) { + if (someip_tp_test::number_of_fragments < 5) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // decrease fourth segment by 16 byte + decrease_segment_back(fragments_request_to_master_[4], 16); + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + // remove the additional inserted bytes which weren't accepted on + // test masterside as they were overlapping + if (mode == ASCENDING) { + decrease_segment_front_back(fragments_request_to_master_[2], 16); + decrease_segment_front(fragments_request_to_master_[4], 16); + } else { + decrease_segment_front_back(fragments_request_to_master_[4], 16); + } + } + vsomeip::message_buffer_t its_request = create_full_message(fragments_request_to_master_); + if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160), + its_request.size()); + } else { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size, + its_request.size()); + } + if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP && mode == ASCENDING) { + // response contains the additional 16 bytes of 2nd fragment instead + // of beginning of the 3rd fragment + for (std::uint32_t i = 0; i < 16; i++) { + its_request[VSOMEIP_PAYLOAD_POS + 2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff; + } + } + + // create complete message from response + vsomeip::message_buffer_t its_response = create_full_message(fragments_response_of_master_); + if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160), + its_response.size()); + } else { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size, + its_response.size()); + } + // change message type of response to request again + its_response[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<vsomeip::byte_t>(vsomeip::message_type_e::MT_REQUEST); + // request and response should now be equal + EXPECT_EQ(its_response.size(), its_request.size()); + EXPECT_EQ(its_response, its_request); + EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_response[0]), + static_cast<void*>(&its_request[0]), + its_response.size())); + fragments_response_of_master_.clear(); + } + } + wait_for_all_response_fragments_received_ = true; + } + fragments_request_to_master_.clear(); + } + + while (wait_for_all_event_fragments_received_) { + if (std::cv_status::timeout == + all_fragments_received_cond_.wait_for(its_lock, + std::chrono::seconds(20))) { + ADD_FAILURE() << "Didn't receive fragmented event from " + " master within time"; + } + } + // check if received event is correct + { + EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_event_from_master_.size()); + // create complete message from event + vsomeip::message_buffer_t its_event = create_full_message(fragments_event_from_master_); + vsomeip::session_t its_event_session = vsomeip::bithelper::read_uint16_be(&its_event[VSOMEIP_SESSION_POS_MIN]); + + std::vector<vsomeip::message_buffer_ptr_t> its_cmp_event_fragments; + create_fragments(someip_tp_test::number_of_fragments, + someip_tp_test::service.service_id, + someip_tp_test::service.instance_id, + someip_tp_test::service.event_id, + vsomeip::message_type_e::MT_NOTIFICATION, + 0x0, its_event_session, &its_cmp_event_fragments, + (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) ? + vsomeip::tp::tp::tp_max_segment_length_ - 160 : + vsomeip::tp::tp::tp_max_segment_length_); + vsomeip::message_buffer_t its_cmp_event = create_full_message(its_cmp_event_fragments); + EXPECT_EQ(its_cmp_event.size(), its_event.size()); + EXPECT_EQ(its_cmp_event, its_event); + EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_cmp_event[0]), + static_cast<void*>(&its_event[0]), + its_cmp_event.size())); + } + its_lock.unlock(); + udp_client_receive_thread.join(); + } catch (const std::exception& _e) { + ADD_FAILURE() << "catched exception: " << _e.what(); + } + }); + + std::mutex all_fragments_received_as_server_mutex_; + std::unique_lock<std::mutex> all_fragments_received_as_server_lock(all_fragments_received_as_server_mutex_); + std::condition_variable all_fragments_received_as_server_cond_; + std::atomic<bool> wait_for_all_fragments_received_as_server_(true); + std::atomic<std::uint16_t> remote_client_request_port(0); + + std::thread udp_server_send_thread([&]() { + // wait until client subscribed + if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) { + ADD_FAILURE() << "Client didn't subscribe within time"; + return; + } + + // send fragmented event to the master + boost::asio::ip::udp::socket::endpoint_type master_client(address_remote_, remote_client_subscription_port); + for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) { + create_fragments(someip_tp_test::number_of_fragments, + someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.event_id, + vsomeip::message_type_e::MT_NOTIFICATION, + vsomeip::ANY_CLIENT, 0xffff, + &fragments_event_to_master_, + (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ? + vsomeip::tp::tp::tp_max_segment_length_ - 160 : + vsomeip::tp::tp::tp_max_segment_length_); + if (mode == order_e::ASCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {2, 3, 5, 1, 4, 0}; + std::cout << __LINE__ << ": using following predefined sequence to send event to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {0,2,4,5,1,3}; + std::cout << __LINE__ << ": using following predefined sequence to send event to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase second segment by 16 byte at front and back + increase_segment_front_back(fragments_event_to_master_[1], 16); + increase_segment_front(fragments_event_to_master_[3], 16); + + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_event_to_master_.begin(); + iter != fragments_event_to_master_.end(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send insert 2nd fragment twice + if (iter == fragments_event_to_master_.begin() + 1) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send oversized fragment as well + increase_segment_back(*iter, 4); + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + decrease_segment_back(*iter, 4); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 3) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send an event fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_event_to_master_[2]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x44; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x44; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + // send a request with a different service ID as well to test cleanup + msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xdd; + msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xdd; + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xdd; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xdd; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // increase second segment by 16 byte + increase_segment_back(fragments_event_to_master_[1], 16); + + // send one oversize message as well + std::vector<vsomeip::message_buffer_ptr_t> oversized_event; + create_fragments(someip_tp_test::number_of_fragments + 1, + someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.event_id, + vsomeip::message_type_e::MT_NOTIFICATION, + vsomeip::ANY_CLIENT, 0xffff, + &oversized_event, + vsomeip::tp::tp::tp_max_segment_length_); + for (const auto& fragment : oversized_event) { + udp_server_socket.send_to(boost::asio::buffer(*fragment), master_client); + } + } + for (const auto& fragment : fragments_event_to_master_) { + udp_server_socket.send_to(boost::asio::buffer(*fragment), master_client); + } + } + } else if (mode == order_e::DESCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments); + std::cout << __LINE__ << ": using following random sequence to send event to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for ( int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client); + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {5,3,2,1,0,4}; + std::cout << __LINE__ << ": using following predefined sequence to send event to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase second last segment by 16 byte at front and back + increase_segment_front_back(fragments_event_to_master_[4], 16); + // update length + *(reinterpret_cast<vsomeip::length_t*>(&((*fragments_event_to_master_[4])[VSOMEIP_LENGTH_POS_MIN]))) = + htonl(static_cast<vsomeip::length_t>(fragments_event_to_master_[4]->size() - VSOMEIP_SOMEIP_HEADER_SIZE)); + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_event_to_master_.rbegin(); + iter != fragments_event_to_master_.rend(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send insert 2nd last fragment twice + if (iter == fragments_event_to_master_.rbegin() + 1) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 4) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send an event fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_event_to_master_[3]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x55; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x55; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + // send a request with a different service ID as well to test cleanup + msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xbb; + msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xbb; + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xbb; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xbb; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 5) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // increase second last segment by 16 byte + increase_segment_back(fragments_event_to_master_[4], 16); + } + for (auto iter = fragments_event_to_master_.rbegin(); iter != fragments_event_to_master_.rend(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + } + } + } + std::cout << __LINE__ << ": send event to master " << std::uint32_t(mode) << std::endl; + } + + for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) { + while (wait_for_all_fragments_received_as_server_) { + if (std::cv_status::timeout == + all_fragments_received_as_server_cond_.wait_for(all_fragments_received_as_server_lock, + std::chrono::seconds(20))) { + ADD_FAILURE() << "Didn't receive request from client within time: " << std::uint32_t(mode); + return; + } else { + EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_received_as_server_.size()); + // create complete message from request of client + vsomeip::message_buffer_t its_request = create_full_message(fragments_received_as_server_); + if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160), + its_request.size()); + } else { + EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE + + someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size, + its_request.size()); + } + const vsomeip::client_t its_request_client = vsomeip::bithelper::read_uint16_be(&its_request[VSOMEIP_CLIENT_POS_MIN]); + const vsomeip::session_t its_request_session = vsomeip::bithelper::read_uint16_be(&its_request[VSOMEIP_SESSION_POS_MIN]); + + create_fragments(someip_tp_test::number_of_fragments, + someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.method_id, + vsomeip::message_type_e::MT_RESPONSE, + its_request_client, + its_request_session, + &fragments_response_to_master_, + (test_mode_ == someip_tp_test::test_mode_e::OVERLAP || + test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ? + vsomeip::tp::tp::tp_max_segment_length_ - 160: + vsomeip::tp::tp::tp_max_segment_length_); + // create complete message from response + vsomeip::message_buffer_t its_response = create_full_message(fragments_response_to_master_); + // change the message type of the response to request for comparison + its_response[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<vsomeip::byte_t>(vsomeip::message_type_e::MT_REQUEST); + + EXPECT_EQ(its_response.size(), its_request.size()); + EXPECT_EQ(its_response, its_request); + EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_response[0]), + static_cast<void*>(&its_request[0]), + its_response.size())); + // send back response + fragments_received_as_server_.clear(); + EXPECT_GT(remote_client_request_port, 0); + boost::asio::ip::udp::socket::endpoint_type master_client(address_remote_, remote_client_request_port); + if (mode == order_e::ASCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {4,2,0,1,3,5}; + std::cout << __LINE__ << ": using following predefined sequence to send back response to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {0,2,4,3,5,1}; + std::cout << __LINE__ << ": using following predefined sequence to send response to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase fourth segment by 16 byte at front and back + increase_segment_front_back(fragments_response_to_master_[3], 16); + increase_segment_front(fragments_response_to_master_[1], 16); + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_response_to_master_.begin(); + iter != fragments_response_to_master_.end(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send 2nd fragment twice + if (iter == fragments_response_to_master_.begin() + 1) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send a fragment with invalid segment size as well + decrease_segment_back(*iter, 16); + increase_segment_back(*iter, 7); + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + increase_segment_back(*iter, 9); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 5) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send an event fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_response_to_master_[4]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x99; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x99; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + // send a request with a different service ID as well to test cleanup + msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xaa; + msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xaa; + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xaa; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xaa; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // increase second segment by 16 byte + increase_segment_back(fragments_response_to_master_[1], 16); + } + for (const auto& frag : fragments_response_to_master_) { + udp_server_socket.send_to(boost::asio::buffer(*frag), master_client); + } + } + } else if (mode == order_e::DESCENDING) { + if (test_mode_ == someip_tp_test::test_mode_e::MIXED) { + std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments); + std::cout << __LINE__ << ": using following random sequence to send back response to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + for ( int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client); + } + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) { + if (someip_tp_test::number_of_fragments != 6) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + } else { + auto its_indexes = {5,3,2,1,4,0}; + std::cout << __LINE__ << ": using following predefined sequence to send response to master: "; + for (auto i : its_indexes) { std::cout << i << ", "; } + std::cout << std::endl; + // increase fith segment by 16 byte at front and back + increase_segment_front_back(fragments_response_to_master_[4], 16); + for (int i : its_indexes) { + udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client); + } + } + } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) { + if (someip_tp_test::number_of_fragments < 2) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + for (auto iter = fragments_response_to_master_.rbegin(); + iter != fragments_response_to_master_.rend(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + // send insert 2nd last fragment twice + if (iter == fragments_response_to_master_.rbegin() + 1) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + } + } + } else { + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + if (someip_tp_test::number_of_fragments < 4) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // send an event fragment with a different session ID first + vsomeip::message_buffer_t msg_incomplete(*fragments_response_to_master_[3]); + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x66; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x66; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + // send a request with a different service ID as well to test cleanup + msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xef; + msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xef; + msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xef; + msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xef; + udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client); + } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (someip_tp_test::number_of_fragments < 5) { + ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed"; + return; + } + // increase second last segment by 16 byte + increase_segment_back(fragments_response_to_master_[4], 16); + } + for (auto iter = fragments_response_to_master_.rbegin(); + iter != fragments_response_to_master_.rend(); iter++) { + udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client); + } + } + } + } + } + wait_for_all_fragments_received_as_server_ = true; + } + }); + + std::thread udp_server_receive_thread([&]() { + { + std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex); + offer_service(&udp_sd_socket); + } + + bool keep_receiving(true); + std::vector<std::uint8_t> receive_buffer(4096); + while (keep_receiving) { + boost::system::error_code error; + boost::asio::ip::udp::socket::endpoint_type its_remote_endpoint; + std::size_t bytes_transferred = udp_server_socket.receive_from( + boost::asio::buffer(receive_buffer, receive_buffer.capacity()), its_remote_endpoint, 0, error); + if (error) { + keep_receiving = false; + ADD_FAILURE() << __func__ << " error: " << error.message(); + return; + } else { + remote_client_request_port = its_remote_endpoint.port(); + std::uint32_t its_pos = 0; + while (bytes_transferred > 0) { + const std::uint32_t its_message_size = vsomeip::bithelper::read_uint32_be( + &receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN]) + + VSOMEIP_SOMEIP_HEADER_SIZE; + + std::cout << __LINE__ << ": received request from master " << its_message_size << std::endl; + + vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0); + vsomeip::service_t its_service = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN]); + vsomeip::method_t its_method = vsomeip::bithelper::read_uint16_be(&receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN]); + + EXPECT_EQ(someip_tp_test::service_slave.service_id, its_service); + EXPECT_EQ(someip_tp_test::service_slave.method_id, its_method); + vsomeip::message_impl msg; + EXPECT_TRUE(msg.deserialize(&its_deserializer)); + if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS])) { + auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size); + + fragments_received_as_server_.push_back(its_buffer); + if (fragments_received_as_server_.size() == someip_tp_test::number_of_fragments) { + std::lock_guard<std::mutex> its_lock(all_fragments_received_as_server_mutex_); + wait_for_all_fragments_received_as_server_ = false; + std::cout << __LINE__ << ": received all fragments as server" << std::endl; + all_fragments_received_as_server_cond_.notify_one(); + static int received_requests = 0; + if (++received_requests == 2) { + std::cout << __LINE__ << ": received all requests as server --> Finished" << std::endl; + keep_receiving = false; + } + } + } + its_pos += its_message_size; + bytes_transferred -= its_message_size; + } + } + } + }); + + send_thread.join(); + sd_receive_thread.join(); + udp_server_receive_thread.join(); + udp_server_send_thread.join(); + + if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) { + std::cout << "Sleeping to let cleanup for unfinished TP message " + "trigger on master side..." << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(11)); + } + // shutdown the server + call_shutdown_method(); + + boost::system::error_code ec; + udp_sd_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_sd_socket.close(ec); + udp_client_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_client_socket.close(ec); + udp_server_socket.shutdown(boost::asio::socket_base::shutdown_both, ec); + udp_server_socket.close(ec); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + if(argc < 3) { + std::cerr << "Please pass an target, local IP address and test mode to this binary like: " + << argv[0] << " 10.0.3.1 10.0.3.202 TP_IN_SEQUENCE" << std::endl; + std::cerr << "Testmodes are [ IN_SEQUENCE, MIXED, INCOMPLETE, OVERLAP, OVERLAP_FRONT_BACK ]" << std::endl; + } else { + remote_address = argv[1]; + local_address = argv[2]; + std::string its_testmode = argv[3]; + if (its_testmode == std::string("IN_SEQUENCE")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/0"; + } else if (its_testmode == std::string("MIXED")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/1"; + } else if (its_testmode == std::string("INCOMPLETE")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/2"; + } else if (its_testmode == std::string("DUPLICATE")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/3"; + } else if (its_testmode == std::string("OVERLAP")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/4"; + } else if (its_testmode == std::string("OVERLAP_FRONT_BACK")) { + ::testing::GTEST_FLAG(filter) = "*send_in_mode/5"; + } + } + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp new file mode 100644 index 00000000000..01a2c973d38 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp @@ -0,0 +1,423 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> +#include <future> +#include <cstring> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> +#include "../../implementation/endpoints/include/tp.hpp" + +#include "someip_tp_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class someip_tp_test_service : public vsomeip_utilities::base_logger { +public: + someip_tp_test_service(struct someip_tp_test::service_info _service_info, someip_tp_test::test_mode_e _testmode) : + vsomeip_utilities::base_logger("STTS", "SOMEIP TP TEST SERVICE"), + service_info_(_service_info), + testmode_(_testmode), + app_(vsomeip::runtime::get()->create_application("someip_tp_test_service")), + wait_until_registered_(true), + wait_until_shutdown_method_called_(true), + wait_for_slave_subscription_(true), + number_notifications_of_slave_(0x0), + wait_for_slave_service_available_(true), + wait_for_two_responses_of_slave_(true), + number_responses_of_slave_(0), + wait_for_two_requests_of_slave_(true), + number_requests_from_slave_(0), + wait_for_two_notifications_of_slave_(true) { + } + + void start() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&someip_tp_test_service::on_state, this, + std::placeholders::_1)); + + // offer field + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(), + false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id, + std::bind(&someip_tp_test_service::on_shutdown_method_called, this, + std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.notify_method_id, + std::bind(&someip_tp_test_service::on_notify_method_called, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, service_info_.method_id, + std::bind(&someip_tp_test_service::on_message, this, + std::placeholders::_1)); + + app_->register_async_subscription_handler(service_info_.service_id, + 0x1, service_info_.eventgroup_id, + std::bind(&someip_tp_test_service::subscription_handler_async, + this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5)); + + // request remote service + app_->request_service(someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id); + its_eventgroups.clear(); + its_eventgroups.insert(someip_tp_test::service_slave.eventgroup_id); + app_->request_event(someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.event_id, its_eventgroups, + vsomeip::event_type_e::ET_EVENT, + vsomeip::reliability_type_e::RT_UNRELIABLE); + app_->register_message_handler(someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.event_id, + std::bind(&someip_tp_test_service::on_notification, this, + std::placeholders::_1)); + app_->subscribe(someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.eventgroup_id, 0x0, + someip_tp_test::service_slave.event_id); + app_->register_availability_handler(someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + std::bind(&someip_tp_test_service::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + app_->register_message_handler( + someip_tp_test::service_slave.service_id, + someip_tp_test::service_slave.instance_id, + someip_tp_test::service_slave.method_id, + std::bind(&someip_tp_test_service::on_response_from_slave, this, + std::placeholders::_1)); + + start_thread_ = std::make_shared<std::thread>([this]() { + app_->start(); + }); + } + + ~someip_tp_test_service() {} + + void offer() { + app_->offer_service(service_info_.service_id, 0x1); + } + + void stop() { + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + app_->clear_all_handler(); + app_->stop(); + + start_thread_->join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _available) { + if (_service == someip_tp_test::service_slave.service_id && + _instance == someip_tp_test::service_slave.instance_id && + _available) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_slave_service_available_ = false; + condition_.notify_one(); + VSOMEIP_INFO << "Service available Service/Instance [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "/" + << std::setw(4) << std::setfill('0') << std::hex << _instance << "]"; + } + } + + void on_message(const std::shared_ptr<vsomeip::message>& _message) { + VSOMEIP_INFO << "Received a message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_session() + << "] size: " << std::dec << _message->get_payload()->get_length(); + auto response = vsomeip::runtime::get()->create_response(_message); + auto payload = vsomeip::runtime::get()->create_payload(_message->get_payload()->get_data(), _message->get_payload()->get_length()); + response->set_payload(payload); + app_->send(response); + if (++number_requests_from_slave_ == 2) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_two_requests_of_slave_ = false; + condition_.notify_one(); + } + } + + void on_notification(const std::shared_ptr<vsomeip::message>& _message) { + VSOMEIP_INFO << "Received a notification with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_session() + << "] size: " << std::dec << _message->get_payload()->get_length(); + EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service()); + EXPECT_EQ(someip_tp_test::service_slave.event_id, _message->get_method()); + std::vector<vsomeip::byte_t> its_cmp_data = + generate_payload(someip_tp_test::number_of_fragments, + (testmode_ == someip_tp_test::test_mode_e::OVERLAP + || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ? + someip_tp_test::max_segment_size - 160 : + someip_tp_test::max_segment_size); + + std::vector<vsomeip::byte_t> its_rcv_data(_message->get_payload()->get_data(), + _message->get_payload()->get_data() + _message->get_payload()->get_length()); + EXPECT_EQ(its_cmp_data.size(), its_rcv_data.size()); + if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (number_notifications_of_slave_ == 0) { //ASCENDING with 2nd segment too big + for (std::uint32_t i = 0; i < 16; i++) { + its_cmp_data[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff; + } + } else if (number_notifications_of_slave_ == 1) { + // DESCENDING with 2nd last segment too big + // no action as successive 4 byte at end of message would + // overwrite the beginning of the last segment which was received first + } + } + EXPECT_EQ(its_cmp_data, its_rcv_data); + EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_cmp_data[0]), + static_cast<void*>(&its_rcv_data[0]), + its_cmp_data.size())); + if (++number_notifications_of_slave_ == 2) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_two_notifications_of_slave_ = false; + condition_.notify_one(); + } + } + + void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + VSOMEIP_WARNING << "************************************************************"; + VSOMEIP_WARNING << "Shutdown method called -> going down!"; + VSOMEIP_WARNING << "************************************************************"; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_shutdown_method_called_ = false; + condition_.notify_one(); + } + + void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) { + (void)_message; + std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments, + (testmode_ == someip_tp_test::test_mode_e::OVERLAP) ? + someip_tp_test::max_segment_size - 160 : + someip_tp_test::max_segment_size); + std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(its_data); + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + VSOMEIP_INFO << __func__ << " send event"; + notify_method_called_.set_value(true); + } + + void send_fragmented_request_to_slave() { + auto its_req = vsomeip::runtime::get()->create_request(); + its_req->set_service(someip_tp_test::service_slave.service_id); + its_req->set_instance(someip_tp_test::service_slave.instance_id); + its_req->set_method(someip_tp_test::service_slave.method_id); + std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments, + (testmode_ == someip_tp_test::test_mode_e::OVERLAP + || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ? + someip_tp_test::max_segment_size - 160 : + someip_tp_test::max_segment_size); + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(its_data); + its_req->set_payload(its_payload); + request_send_to_slave_ = its_req; + app_->send(its_req); + } + + void on_response_from_slave(const std::shared_ptr<vsomeip::message> &_message) { + VSOMEIP_INFO << "Received a response from the slave with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _message->get_session() + << "] size: " << std::dec << _message->get_payload()->get_length(); + EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service()); + EXPECT_EQ(someip_tp_test::service_slave.instance_id, _message->get_instance()); + EXPECT_EQ(someip_tp_test::service_slave.method_id, _message->get_method()); + std::vector<vsomeip::byte_t> its_resp_payload(_message->get_payload()->get_data(), + _message->get_payload()->get_data() + _message->get_payload()->get_length()); + std::vector<vsomeip::byte_t> its_req_payload(request_send_to_slave_->get_payload()->get_data(), + request_send_to_slave_->get_payload()->get_data() + request_send_to_slave_->get_payload()->get_length()); + if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) { + if (number_responses_of_slave_ == 0) { //ASCENDING with 2nd segment too big + for (std::uint32_t i = 0; i < 16; i++) { + its_req_payload[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff; + } + } else if (number_responses_of_slave_ == 1) { + // DESCENDING with 2nd last segment too big + // no action as successive 4 byte at end of message would + // overwrite the beginning of the last segment which was received first + } + } + + EXPECT_EQ(its_req_payload.size(), its_resp_payload.size()); + EXPECT_EQ(its_req_payload, its_resp_payload); + EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_req_payload[0]), + static_cast<void*>(&its_resp_payload[0]), + its_req_payload.size())); + + if (++number_responses_of_slave_ < 2) { + send_fragmented_request_to_slave(); + } else { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_two_responses_of_slave_ = false; + condition_.notify_one(); + } + } + + std::vector<vsomeip::byte_t> generate_payload(std::uint32_t _number_of_fragments, + std::uint32_t _segment_size) { + std::vector<vsomeip::byte_t> its_data; + for (std::uint32_t i = 0; i < _number_of_fragments; i++) { + its_data.resize((i * _segment_size) + _segment_size, + static_cast<std::uint8_t>(i)); + } + return its_data; + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + while (wait_for_slave_service_available_) { + condition_.wait(its_lock); + } + send_fragmented_request_to_slave(); + + while (wait_for_two_responses_of_slave_) { + condition_.wait(its_lock); + } + EXPECT_EQ(2u, number_responses_of_slave_); + + while (wait_for_two_requests_of_slave_) { + condition_.wait(its_lock); + } + EXPECT_EQ(2u, number_requests_from_slave_); + + while (wait_for_two_notifications_of_slave_) { + condition_.wait(its_lock); + } + EXPECT_EQ(2u, number_notifications_of_slave_); + + while (wait_for_slave_subscription_) { + condition_.wait(its_lock); + } + // slave subscribed --> sent a notification + on_notify_method_called(vsomeip::runtime::get()->create_message()); + + while (wait_until_shutdown_method_called_) { + condition_.wait(its_lock); + } + } + + void subscription_handler_async(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, + bool _subscribed, const std::function<void(const bool)>& _cbk) { + (void)_uid; + (void)_gid; + VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed; + static int was_called = 0; + was_called++; + EXPECT_EQ(1, was_called); + EXPECT_TRUE(_subscribed); + _cbk(true); + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_slave_subscription_ = false; + condition_.notify_one(); + } + + +private: + struct someip_tp_test::service_info service_info_; + someip_tp_test::test_mode_e testmode_; + std::shared_ptr<vsomeip::application> app_; + + bool wait_until_registered_; + bool wait_until_shutdown_method_called_; + std::mutex mutex_; + std::condition_variable condition_; + std::atomic<bool> wait_for_slave_subscription_; + std::atomic<std::uint32_t> number_notifications_of_slave_; + std::promise<bool> notify_method_called_; + bool wait_for_slave_service_available_; + bool wait_for_two_responses_of_slave_; + std::uint32_t number_responses_of_slave_; + bool wait_for_two_requests_of_slave_; + std::uint32_t number_requests_from_slave_; + bool wait_for_two_notifications_of_slave_; + std::shared_ptr<vsomeip::message> request_send_to_slave_; + std::shared_ptr<std::thread> start_thread_; +}; + +someip_tp_test::test_mode_e its_testmode(someip_tp_test::test_mode_e::IN_SEQUENCE); + +TEST(someip_someip_tp_test, echo_requests) +{ + someip_tp_test_service its_sample(someip_tp_test::service, its_testmode); + its_sample.start(); + its_sample.run(); + its_sample.stop(); +} + + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if (argc < 2) { + std::cerr << "Please pass a test mode to this binary like: " + << argv[0] << " IN_SEQUENCE" << std::endl; + std::cerr << "Testmodes are [ IN_SEQUENCE, MIXED, INCOMPLETE, DUPLICATE, OVERLAP, OVERLAP_FRONT_BACK ]" << std::endl; + exit(1); + } + + std::string its_pased_testmode = argv[1]; + if (its_pased_testmode == std::string("IN_SEQUENCE")) { + its_testmode = someip_tp_test::test_mode_e::IN_SEQUENCE; + } else if (its_pased_testmode == std::string("MIXED")) { + its_testmode = someip_tp_test::test_mode_e::MIXED; + } else if (its_pased_testmode == std::string("INCOMPLETE")) { + its_testmode = someip_tp_test::test_mode_e::INCOMPLETE; + } else if (its_pased_testmode == std::string("DUPLICATE")) { + its_testmode = someip_tp_test::test_mode_e::DUPLICATE; + } else if (its_pased_testmode == std::string("OVERLAP")) { + its_testmode = someip_tp_test::test_mode_e::OVERLAP; + } else if (its_pased_testmode == std::string("OVERLAP_FRONT_BACK")) { + its_testmode = someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/CMakeLists.txt new file mode 100644 index 00000000000..e929118b4bc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(subscribe_notify_one_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + subscribe_notify_one_test_diff_client_ids_diff_ports_master.json + subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json + subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json + subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json + subscribe_notify_one_test_diff_client_ids_diff_ports_slave_tcp.json + subscribe_notify_one_test_diff_client_ids_diff_ports_slave_udp.json + subscribe_notify_one_test_master_starter.sh + subscribe_notify_one_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(subscribe_notify_one_test_service + subscribe_notify_one_test_service.cpp +) + +# Add build dependencies and link libraries to executables. +targets_add_default_dependencies(subscribe_notify_one_test_service) +targets_link_default_libraries(subscribe_notify_one_test_service) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_one_test_diff_client_ids_diff_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_one_test_master_starter.sh + UDP subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_one_test_diff_client_ids_diff_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_one_test_master_starter.sh + TCP subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_one_test_diff_client_ids_diff_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_one_test_master_starter.sh + TCP_AND_UDP subscribe_notify_one_test_diff_client_ids_diff_ports_master.json +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..dbb8868c6f0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master.json.in @@ -0,0 +1,104 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_one_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_one_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x1111", + "is_field" : "false", + "is_reliable" : "true" + } + ] + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x2222", + "is_field" : "false", + "is_reliable" : "true" + } + ] + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x3333", + "is_field" : "false", + "is_reliable" : "true" + } + ] + } + ], + "routing":"subscribe_notify_one_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_SLAVE@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json.in new file mode 100644 index 00000000000..e535273024c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_tcp.json.in @@ -0,0 +1,77 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_one_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_one_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_one_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_SLAVE@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json.in new file mode 100644 index 00000000000..e2b54b065a0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json.in @@ -0,0 +1,65 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_one_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_one_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003" + } + ], + "routing":"subscribe_notify_one_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_SLAVE@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..a9eeca9ff90 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json.in @@ -0,0 +1,104 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_one_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_one_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x4444", + "is_field" : "false", + "is_reliable" : "true" + } + ] + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x5555", + "is_field" : "false", + "is_reliable" : "true" + } + ] + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + }, + "events" : + [ + { + "event" : "0x6666", + "is_field" : "false", + "is_reliable" : "true" + } + ] + } + ], + "routing":"subscribe_notify_one_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_MASTER@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_tcp.json.in new file mode 100644 index 00000000000..d075a1ed276 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_tcp.json.in @@ -0,0 +1,77 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_one_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_one_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_one_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_MASTER@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_udp.json.in new file mode 100644 index 00000000000..2f9d8bca8ef --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_diff_client_ids_diff_ports_slave_udp.json.in @@ -0,0 +1,65 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_one_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_one_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_one_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006" + } + ], + "routing":"subscribe_notify_one_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + }, + "supports_selective_broadcasts" : + { + "address" : "@TEST_IP_MASTER@" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_master_starter.sh.in new file mode 100755 index 00000000000..ab573ba42f9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_master_starter.sh.in @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ] +then + echo "Please pass a json file and event reliability type to this script." + echo "For example: $0 subscribe_notify_one_test_diff_client_ids_diff_ports_master_udp.json UDP" + exit 1 +fi + +# replace master with slave to be able display the correct json file to be used +# with the slave script +RELIABILITY_TYPE=$1 +MASTER_JSON_FILE=$2 +CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave} + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_one +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_one_test_service 1 $RELIABILITY_TYPE & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_two +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_one_test_service 2 $RELIABILITY_TYPE & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_three +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_one_test_service 3 $RELIABILITY_TYPE & + +sleep 3 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting subscribe_notify_one_test_slave_starter.sh on slave LXC with parameters $CLIENT_JSON_FILE" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/subscribe_notify_one_tests; ./subscribe_notify_one_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./subscribe_notify_one_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** subscribe_notify_one_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** subscribe_notify_one_test_diff_client_ids_diff_ports_master.json and +** subscribe_notify_one_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_slave_starter.sh.in new file mode 100755 index 00000000000..a7764806855 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/conf/subscribe_notify_one_test_slave_starter.sh.in @@ -0,0 +1,51 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ] +then + echo "Please pass a json file and event reliability type to this script." + echo "For example: $0 UDP subscribe_notify_one_test_diff_client_ids_diff_ports_slave_udp.json" + exit 1 +fi + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_four +export VSOMEIP_CONFIGURATION=$2 +./subscribe_notify_one_test_service 4 $1 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_five +export VSOMEIP_CONFIGURATION=$2 +./subscribe_notify_one_test_service 5 $1 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_one_test_service_six +export VSOMEIP_CONFIGURATION=$2 +./subscribe_notify_one_test_service 6 $1 & + +sleep 3 + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp new file mode 100644 index 00000000000..047ded7a1c1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_globals.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ +#define SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ + +namespace subscribe_notify_one_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; +}; + +static constexpr std::array<service_info, 7> service_infos = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 }, + { 0x2222, 0x1, 0x2222, 0x2222, 0x2000 }, + { 0x3333, 0x1, 0x3333, 0x3333, 0x3000 }, + // node 2 + { 0x4444, 0x1, 0x4444, 0x4444, 0x4000 }, + { 0x5555, 0x1, 0x5555, 0x5555, 0x5000 }, + { 0x6666, 0x1, 0x6666, 0x6666, 0x6000 } +}}; + +static constexpr int notifications_to_send = 10; +} + +#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp new file mode 100644 index 00000000000..62742ecdfc9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_one_tests/subscribe_notify_one_test_service.cpp @@ -0,0 +1,499 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <unordered_set> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "subscribe_notify_one_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class subscribe_notify_one_test_service : public vsomeip_utilities::base_logger { +public: + subscribe_notify_one_test_service(struct subscribe_notify_one_test::service_info _service_info, vsomeip::reliability_type_e _reliability_type) : + vsomeip_utilities::base_logger("SNOS", "SUBSCRIBE NOTIFY ONE TEST SERVICE"), + service_info_(_service_info), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + wait_until_other_services_available_(true), + wait_until_notified_from_other_services_(true), + offer_thread_(std::bind(&subscribe_notify_one_test_service::run, this)), + wait_for_stop_(true), + stop_thread_(std::bind(&subscribe_notify_one_test_service::wait_for_stop, this)), + wait_for_notify_(true), + notify_thread_(std::bind(&subscribe_notify_one_test_service::notify_one, this)), + subscription_state_handler_called_(0), + subscription_error_occured_(false), + reliability_type_(_reliability_type) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + app_->register_state_handler( + std::bind(&subscribe_notify_one_test_service::on_state, this, + std::placeholders::_1)); + + // offer event + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, vsomeip::event_type_e::ET_SELECTIVE_EVENT, + std::chrono::milliseconds::zero(), false, true, nullptr, + reliability_type_); + + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&subscribe_notify_one_test_service::on_request, this, + std::placeholders::_1)); + + // register subscription handler to detect whether or not all other + // other services have subscribed + app_->register_subscription_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + std::bind(&subscribe_notify_one_test_service::on_subscription, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + + // register availability for all other services and request their event. + for(const auto& i : subscribe_notify_one_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + app_->register_message_handler(i.service_id, + i.instance_id, vsomeip::ANY_METHOD, + std::bind(&subscribe_notify_one_test_service::on_message, this, + std::placeholders::_1)); + app_->register_availability_handler(i.service_id, i.instance_id, + std::bind(&subscribe_notify_one_test_service::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + app_->request_service(i.service_id, i.instance_id, vsomeip::DEFAULT_MAJOR, vsomeip::DEFAULT_MINOR); + + auto handler = std::bind(&subscribe_notify_one_test_service::on_subscription_state_change, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); + app_->register_subscription_status_handler(i.service_id, i.instance_id, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(vsomeip::ANY_SERVICE, i.instance_id, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(i.service_id, vsomeip::ANY_INSTANCE, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + app_->register_subscription_status_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, i.eventgroup_id, vsomeip::ANY_EVENT, handler); + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(i.eventgroup_id); + app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, vsomeip::event_type_e::ET_SELECTIVE_EVENT, reliability_type_); + + other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false; + other_services_received_notification_[std::make_pair(i.service_id, i.method_id)] = 0; + } + + app_->start(); + } + + ~subscribe_notify_one_test_service() { + offer_thread_.join(); + stop_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + } + + void stop_offer() { + app_->stop_offer_event(service_info_.service_id, service_info_.instance_id, service_info_.event_id); + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_DEBUG << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + condition_.notify_one(); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + auto its_service = other_services_available_.find(std::make_pair(_service, _instance)); + if(its_service != other_services_available_.end()) { + if(its_service->second != _is_available) { + its_service->second = true; + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is available."; + + } + } + + if(std::all_of(other_services_available_.cbegin(), + other_services_available_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::instance_t>, bool>::value_type& v) { + return v.second;})) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_other_services_available_ = false; + condition_.notify_one(); + } + } + } + + void on_subscription_state_change(const vsomeip::service_t _service, const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, const vsomeip::event_t _event, const uint16_t _error) { + (void)_service; + (void)_instance; + (void)_eventgroup; + (void)_event; + if (!_error) { + subscription_state_handler_called_++; + } else { + subscription_error_occured_ = true; + VSOMEIP_ERROR << std::hex << app_->get_client() + << " : on_subscription_state_change: for service " << std::hex + << _service << " received a subscription error!"; + } + + } + + bool on_subscription(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, bool _subscribed) { + (void)_uid; + (void)_gid; + std::lock_guard<std::mutex> its_subscribers_lock(subscribers_mutex_); + + // check if all other services have subscribed: + // -1 for placeholder in array and -1 for the service itself + if (subscribers_.size() == subscribe_notify_one_test::service_infos.size() - 2) { + return true; + } + + if (_subscribed) { + subscribers_.insert(_client); + } else { + subscribers_.erase(_client); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " << "Client: " << _client + << " subscribed, now have " << std::dec << subscribers_.size() + << " subscribers. Expecting " << std::dec + << subscribe_notify_one_test::service_infos.size() - 2; + + if (subscribers_.size() == subscribe_notify_one_test::service_infos.size() - 2) + { + // notify the notify thread to start sending out notifications + std::lock_guard<std::mutex> its_lock(notify_mutex_); + wait_for_notify_ = false; + notify_condition_.notify_one(); + } + return true; + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) { + VSOMEIP_DEBUG << "Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "]"; + std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get() + ->create_response(_message); + app_->send(its_response); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if (_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + + other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())]++; + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " + << "Received a notification with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "] (now have: " + << std::dec << other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())] << ")"; + + if (all_notifications_received()) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + stop_condition_.notify_one(); + } + } + } + + bool all_notifications_received() { + return std::all_of( + other_services_received_notification_.cbegin(), + other_services_received_notification_.cend(), + [&](const std::map<std::pair<vsomeip::service_t, + vsomeip::method_t>, std::uint32_t>::value_type& v) + { + return v.second == subscribe_notify_one_test::notifications_to_send; + } + ); + } + + bool all_notifications_received_tcp_and_udp() { + std::uint32_t received_twice(0); + std::uint32_t received_normal(0); + for(const auto &v : other_services_received_notification_) { + if (v.second == subscribe_notify_one_test::notifications_to_send * 2) { + received_twice++; + } else if(v.second == subscribe_notify_one_test::notifications_to_send) { + received_normal++; + } + } + + if( received_twice == (subscribe_notify_one_test::service_infos.size() - 1) / 2 + && received_normal == (subscribe_notify_one_test::service_infos.size() - 1) / 2 - 1) { + // routing manager stub receives the notification + // - twice from external nodes + // - and normal from all internal nodes + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " + << "Received notifications:" + << " Normal: " << received_normal + << " Twice: " << received_twice; + return true; + } + return false; + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + + while (wait_until_other_services_available_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Subscribing"; + // subscribe to events of other services + uint32_t subscribe_count = 0; + for(const subscribe_notify_one_test::service_info& i: subscribe_notify_one_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + + ++subscribe_count; + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR); + + VSOMEIP_DEBUG << "[" << std::hex << service_info_.service_id + << "] subscribing to Service/Instance/Eventgroup [" + << std::setw(4) << std::setfill('0') << std::hex << i.service_id << "/" + << std::setw(4) << std::setfill('0') << std::hex << i.instance_id + << "/" << std::setw(4) << std::setfill('0') << std::hex << i.eventgroup_id << "]"; + + } + + while (wait_until_notified_from_other_services_) { + condition_.wait(its_lock); + } + + // It is possible that we run in the case a subscription is NACKED + // due to TCP endpoint not completely connected when subscription + // is processed in the server - due to resubscribing the error handler + // count may differ from expected value, but its not a real but as + // the subscription takes places anyways and all events will be received. + if (!subscription_error_occured_) { + // 4 * subscribe count cause we installed three additional wild-card handlers + ASSERT_EQ(subscribe_count * 4, subscription_state_handler_called_); + } else { + VSOMEIP_ERROR << "Subscription state handler check skipped: CallCount=" + << std::dec << subscription_state_handler_called_; + } + } + + void notify_one() { + std::unique_lock<std::mutex> its_lock(notify_mutex_); + while(wait_for_notify_) { + notify_condition_.wait(its_lock); + } + + // sleep a while before starting to notify this is necessary as it's not + // possible to detect if _all_ clients on the remote side have + // successfully subscribed as we only receive once subscription per + // remote node no matter how many clients subscribed to this eventgroup + // on the remote node + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + for(uint32_t i = 0; i < subscribe_notify_one_test::notifications_to_send; i++) { + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + + vsomeip::byte_t its_data[10] = {0}; + for (uint32_t j = 0; j < i+1; ++j) { + its_data[j] = static_cast<uint8_t>(j); + } + its_payload->set_data(its_data, i+1); + + for (vsomeip::client_t client : subscribers_) { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Notifying client: " + << client << " : " << i+1; + app_->notify_one(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload, client); + } + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] Received notifications from all other services, going down"; + + // wait until all notifications have been sent out + notify_thread_.join(); + + // let offer thread exit + { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_notified_from_other_services_ = false; + condition_.notify_one(); + } + + stop_offer(); + + // ensure that the service which hosts the routing doesn't exit to early + if (app_->is_routing()) { + for (const auto& i : subscribe_notify_one_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + while (app_->is_available(i.service_id, i.instance_id, + vsomeip::ANY_MAJOR, vsomeip::ANY_MINOR)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + + for(const auto& i : subscribe_notify_one_test::service_infos) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + app_->unregister_subscription_status_handler(i.service_id, i.instance_id, + i.eventgroup_id, vsomeip::ANY_EVENT); + app_->unsubscribe(i.service_id, i.instance_id, i.eventgroup_id); + app_->release_event(i.service_id, i.instance_id, i.event_id); + app_->release_service(i.service_id, i.instance_id); + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + app_->clear_all_handler(); + app_->stop(); + } + +private: + subscribe_notify_one_test::service_info service_info_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_; + + bool wait_until_registered_; + bool wait_until_other_services_available_; + bool wait_until_notified_from_other_services_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; + + bool wait_for_notify_; + std::mutex notify_mutex_; + std::condition_variable notify_condition_; + std::thread notify_thread_; + + std::unordered_set<vsomeip::client_t> subscribers_; + std::atomic<uint32_t> subscription_state_handler_called_; + std::atomic<bool> subscription_error_occured_; + + std::mutex subscribers_mutex_; + vsomeip::reliability_type_e reliability_type_; +}; + +static unsigned long service_number; +vsomeip::reliability_type_e reliability_type = vsomeip::reliability_type_e::RT_UNKNOWN; + + +TEST(someip_subscribe_notify_one_test, send_ten_notifications_to_service) +{ + subscribe_notify_one_test_service its_sample( + subscribe_notify_one_test::service_infos[service_number], + reliability_type); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 3) { + std::cerr << "Please specify a service number and event reliability type, like: " << argv[0] << " 2 UDP" << std::endl; + std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl; + std::cerr << "Valid service reliability types are [UDP, TCP, TCP_AND_UDP]" << std::endl; + + return 1; + } + + service_number = std::stoul(std::string(argv[1]), nullptr); + + if (std::string("TCP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_RELIABLE; + } else if (std::string("UDP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_UNRELIABLE; + } else if (std::string("TCP_AND_UDP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_BOTH; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/CMakeLists.txt new file mode 100644 index 00000000000..6ee2ae3d7d3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/CMakeLists.txt @@ -0,0 +1,275 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(subscribe_notify_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_master.json + subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json + subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp.json + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_slave.json + subscribe_notify_test_diff_client_ids_diff_ports_slave_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp_local_tcp.json + subscribe_notify_test_diff_client_ids_diff_ports_slave_udp.json + subscribe_notify_test_diff_client_ids_diff_ports_slave_udp_local_tcp.json + subscribe_notify_test_diff_client_ids_partial_same_ports_master.json + subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json + subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json + subscribe_notify_test_diff_client_ids_partial_same_ports_slave_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_master.json + subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_master_udp.json + subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_slave.json + subscribe_notify_test_diff_client_ids_same_ports_slave_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_slave_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_slave_tcp_local_tcp.json + subscribe_notify_test_diff_client_ids_same_ports_slave_udp.json + subscribe_notify_test_diff_client_ids_same_ports_slave_udp_local_tcp.json + subscribe_notify_test_master_starter.sh + subscribe_notify_test_one_event_two_eventgroups_master.json + subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json + subscribe_notify_test_one_event_two_eventgroups_master_starter.sh + subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh + subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json + subscribe_notify_test_one_event_two_eventgroups_tcp_slave_local_tcp.json + subscribe_notify_test_one_event_two_eventgroups_udp_slave.json + subscribe_notify_test_one_event_two_eventgroups_udp_slave_local_tcp.json + subscribe_notify_test_same_client_ids_diff_ports_master.json + subscribe_notify_test_same_client_ids_diff_ports_master_local_tcp.json + subscribe_notify_test_same_client_ids_diff_ports_slave.json + subscribe_notify_test_same_client_ids_diff_ports_slave_local_tcp.json + subscribe_notify_test_same_client_ids_same_ports_master.json + subscribe_notify_test_same_client_ids_same_ports_master_local_tcp.json + subscribe_notify_test_same_client_ids_same_ports_slave.json + subscribe_notify_test_same_client_ids_same_ports_slave_local_tcp.json + subscribe_notify_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(subscribe_notify_test_service + subscribe_notify_test_service.cpp +) + +# Add test executable. +add_executable(subscribe_notify_test_one_event_two_eventgroups_service + subscribe_notify_test_one_event_two_eventgroups_service.cpp +) + +# Add test executable. +add_executable(subscribe_notify_test_one_event_two_eventgroups_client + subscribe_notify_test_one_event_two_eventgroups_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + subscribe_notify_test_service + subscribe_notify_test_one_event_two_eventgroups_service + subscribe_notify_test_one_event_two_eventgroups_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Subscribe Notify Tests - Local Communication over UDS + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP + subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_diff_ports_master.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_same_ports_master_udp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP + subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_same_ports_master.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_partial_same_ports_master.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json + SAME_SERVICE_ID +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json +) + +# Subscribe Notify Tests - Local Communication over TCP + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_tcp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP + subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_both_tcp_and_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_tcp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP + subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_same_ports_both_tcp_and_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_partial_same_ports_both_tcp_and_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + TCP_AND_UDP + subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json + SAME_SERVICE_ID +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_master_starter.sh + UDP + subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json +) + +# Subscribe Notify Tests - One Event Two Eventgroups + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_one_event_two_eventgroups_udp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh + UDP + subscribe_notify_test_one_event_two_eventgroups_master.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_one_event_two_eventgroups_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh + TCP + subscribe_notify_test_one_event_two_eventgroups_master.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_one_event_two_eventgroups_udp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh + UDP + subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json +) + +# Add custom test command. +add_custom_test( + NAME subscribe_notify_test_one_event_two_eventgroups_tcp_local_tcp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh + TCP + subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in new file mode 100644 index 00000000000..6cd1b038011 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master.json.in @@ -0,0 +1,60 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json.in new file mode 100644 index 00000000000..e24a420c47e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_master_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing" : + { + "host" : + { + "unicast" : "127.0.0.1", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in new file mode 100644 index 00000000000..db8dd46094c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave.json.in @@ -0,0 +1,60 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave_local_tcp.json.in new file mode 100644 index 00000000000..da17c41e11a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_autoconfig_slave_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing" : + { + "host" : + { + "unicast" : "127.0.0.1", + "port" : "31490" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..07cfdcc8678 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json.in new file mode 100644 index 00000000000..3e89dff6a0a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json.in new file mode 100644 index 00000000000..7223363ce28 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp.json.in @@ -0,0 +1,73 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json.in new file mode 100644 index 00000000000..3d554edf323 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_tcp_local_tcp.json.in @@ -0,0 +1,80 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json.in new file mode 100644 index 00000000000..6eca929e2e9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003" + } + ], + "routing": "subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json.in new file mode 100644 index 00000000000..7cf72268552 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_master_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json.in new file mode 100644 index 00000000000..aaa59150de2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x1111", + "instance":"0x0002", + "unreliable":"30002" + }, + { + "service":"0x1111", + "instance":"0x0003", + "unreliable":"30003" + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json.in new file mode 100644 index 00000000000..decd4fe88f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_master_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001" + }, + { + "service":"0x1111", + "instance":"0x0002", + "unreliable":"30002" + }, + { + "service":"0x1111", + "instance":"0x0003", + "unreliable":"30003" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp.json.in new file mode 100644 index 00000000000..d40783cc83b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x2222", + "instance":"0x0002", + "unreliable":"30005" + }, + { + "service":"0x2222", + "instance":"0x0003", + "unreliable":"30006" + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp_local_tcp.json.in new file mode 100644 index 00000000000..4498037beaa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_same_service_id_slave_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x2222", + "instance":"0x0002", + "unreliable":"30005" + }, + { + "service":"0x2222", + "instance":"0x0003", + "unreliable":"30006" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..d943ef864b1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_local_tcp.json.in new file mode 100644 index 00000000000..3dd7ded3140 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp.json.in new file mode 100644 index 00000000000..7b010e8185b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp.json.in @@ -0,0 +1,73 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp_local_tcp.json.in new file mode 100644 index 00000000000..75ffad90cb8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_tcp_local_tcp.json.in @@ -0,0 +1,85 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1", + "port" : "44000" + }, + "guests" : + { + "ports" : [ { "first" : "44100", "last" : "44105" } ] + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp.json.in new file mode 100644 index 00000000000..7bb0a61d2f4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006" + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp_local_tcp.json.in new file mode 100644 index 00000000000..737cbffeccd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_diff_ports_slave_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in new file mode 100644 index 00000000000..db58021047b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json.in new file mode 100644 index 00000000000..ee0a61abe99 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_master_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in new file mode 100644 index 00000000000..8f1c0603dc2 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave_local_tcp.json.in new file mode 100644 index 00000000000..20d92cd91c7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_partial_same_ports_slave_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..07f2a2ce1bc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json.in new file mode 100644 index 00000000000..2b476cfe546 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json.in new file mode 100644 index 00000000000..adfb4c39d20 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp.json.in @@ -0,0 +1,73 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json.in new file mode 100644 index 00000000000..0ff472a61c8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_tcp_local_tcp.json.in @@ -0,0 +1,80 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp.json.in new file mode 100644 index 00000000000..cddd880dbcd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000" + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json.in new file mode 100644 index 00000000000..0876c590c22 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_master_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..40ab1359cf3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_local_tcp.json.in new file mode 100644 index 00000000000..58a75150b09 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp.json.in new file mode 100644 index 00000000000..1b36defc390 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp.json.in @@ -0,0 +1,73 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp_local_tcp.json.in new file mode 100644 index 00000000000..1565cc87841 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_tcp_local_tcp.json.in @@ -0,0 +1,80 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp.json.in new file mode 100644 index 00000000000..e035bb3f15c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp.json.in @@ -0,0 +1,61 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000" + } + ], + "routing": "subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp_local_tcp.json.in new file mode 100644 index 00000000000..af0c897539f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_diff_client_ids_same_ports_slave_udp_local_tcp.json.in @@ -0,0 +1,68 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x4444" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x5555" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x6666" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000" + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000" + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_master_starter.sh.in new file mode 100755 index 00000000000..aa4f4fc204b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_master_starter.sh.in @@ -0,0 +1,85 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file and event reliability type to this script." + echo "For example: $0 UDP subscribe_notify_test_diff_client_ids_diff_ports_master.json" + echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter" + exit 1 +fi + +# replace master with slave to be able display the correct json file to be used +# with the slave script +RELIABILITY_TYPE=$1 +MASTER_JSON_FILE=$2 +SAME_SERVICE_ID=$3 +CLIENT_JSON_FILE=${MASTER_JSON_FILE/master/slave} + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_one +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_test_service 1 $RELIABILITY_TYPE $3 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_two +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_test_service 2 $RELIABILITY_TYPE $3 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_three +export VSOMEIP_CONFIGURATION=$MASTER_JSON_FILE +./subscribe_notify_test_service 3 $RELIABILITY_TYPE $3 & + +sleep 3 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting subscribe_notify_test_slave_starter.sh on slave LXC with parameters $CLIENT_JSON_FILE $2" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/subscribe_notify_tests; ./subscribe_notify_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE $3\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./subscribe_notify_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE $3" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** subscribe_notify_test_slave_starter.sh $RELIABILITY_TYPE $CLIENT_JSON_FILE $3 +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** $MASTER_JSON_FILE and +** $CLIENT_JSON_FILE to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# Wait until client and service are finished +for job in $(jobs -p) +do + # Fail gets incremented if either client or service exit + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in new file mode 100644 index 00000000000..1133326bff3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master.json.in @@ -0,0 +1,31 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_client", + "id" : "0x9999" + } + ], + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json.in new file mode 100644 index 00000000000..cbb06f22533 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_local_tcp.json.in @@ -0,0 +1,38 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_client", + "id" : "0x9999" + } + ], + "routing" : + { + "host" : + { + "name" : "routingmanagerd", + "unicast" : "127.0.0.1" + } + }, + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh.in new file mode 100755 index 00000000000..68fd9560963 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_master_starter.sh.in @@ -0,0 +1,84 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ]; then + echo "Please pass a json file and a subscription type to this script." + echo "Valid subscription types include:" + echo " [UDP, TCP]" + echo "For example: $0 UDP subscribe_notify_test_one_event_two_eventgroups_master.json" + exit 1 +fi + +# replace master with slave to be able display the correct json file to be used +# with the slave script +RELIABILITY_TYPE=$1 +MASTER_JSON_FILE=$2 +if [ $1 == "UDP" ]; then + SLAVE_JSON_FILE=${MASTER_JSON_FILE/master/udp_slave} +elif [ $1 == "TCP" ]; then + SLAVE_JSON_FILE=${MASTER_JSON_FILE/master/tcp_slave} +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$2 +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +# Start the client +./subscribe_notify_test_one_event_two_eventgroups_client $1 & +PID_CLIENT=$! +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting subscribe_notify_test_slave_starter.sh on slave LXC with parameters $SLAVE_JSON_FILE" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/subscribe_notify_tests; ./subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $RELIABILITY_TYPE $SLAVE_JSON_FILE\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $RELIABILITY_TYPE $SLAVE_JSON_FILE" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh $RELIABILITY_TYPE $SLAVE_JSON_FILE +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** subscribe_notify_test_diff_client_ids_diff_ports_master.json and +** subscribe_notify_test_diff_client_ids_diff_ports_slave.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# wait until client exits successfully +wait $PID_CLIENT || FAIL=$(($FAIL+1)) + + +# kill daemon +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD || FAIL=$(($FAIL+1)) + +echo "" + +# Check if both exited successfully +if [ $FAIL -eq 0 ]; then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh.in new file mode 100755 index 00000000000..7567a9bfc61 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_slave_starter.sh.in @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 2 ]; then + echo "Please pass a json file and a subscription type to this script." + echo "Valid subscription types include:" + echo " [UDP, TCP]" + echo "For example: $0 UDP subscribe_notify_test_one_event_two_eventgroups_udp_slave.json" + exit 1 +fi + +FAIL=0 + +export VSOMEIP_CONFIGURATION=$2 +# start daemon +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +# Start the services +./subscribe_notify_test_one_event_two_eventgroups_service $1 & +PID_SERVICE=$! + +# wait until service exits successfully +wait $PID_SERVICE || FAIL=$(($FAIL+1)) + + +# kill daemon +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD || FAIL=$(($FAIL+1)) + +echo "" + +# Check if both exited successfully +if [ $FAIL -eq 0 ]; then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in new file mode 100644 index 00000000000..acfcc06cafd --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave.json.in @@ -0,0 +1,39 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "reliable" : { "port":"30509", "enable-magic-cookies":"false" } + } + ], + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave_local_tcp.json.in new file mode 100644 index 00000000000..405912a92e7 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_tcp_slave_local_tcp.json.in @@ -0,0 +1,46 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "info", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "reliable" : { "port":"30509", "enable-magic-cookies":"false" } + } + ], + "routing" : + { + "host" : + { + "name" : "routingmanagerd", + "unicast" : "127.0.0.1" + } + }, + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in new file mode 100644 index 00000000000..2249cbfbe51 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave.json.in @@ -0,0 +1,39 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "unreliable" : "30509" + } + ], + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave_local_tcp.json.in new file mode 100644 index 00000000000..7319c318224 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_one_event_two_eventgroups_udp_slave_local_tcp.json.in @@ -0,0 +1,46 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "logging" : + { + "level" : "warning", + "console" : "true", + "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "subscribe_notify_test_service", + "id" : "0x8888" + } + ], + "services" : + [ + { + "service" : "0xcafe", + "instance" : "0x1", + "unreliable" : "30509" + } + ], + "routing" : + { + "host" : + { + "name" : "routingmanagerd", + "unicast" : "127.0.0.1" + } + }, + "service-discovery" : + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "0", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in new file mode 100644 index 00000000000..07cfdcc8678 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master_local_tcp.json.in new file mode 100644 index 00000000000..3e89dff6a0a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_master_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30001", + "reliable": + { + "port":"40001", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30002", + "reliable": + { + "port":"40002", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30003", + "reliable": + { + "port":"40003", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in new file mode 100644 index 00000000000..f213ba95136 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave_local_tcp.json.in new file mode 100644 index 00000000000..75f7ad2c678 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_diff_ports_slave_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"info", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30004", + "reliable": + { + "port":"40004", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30005", + "reliable": + { + "port":"40005", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30006", + "reliable": + { + "port":"40006", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in new file mode 100644 index 00000000000..07f2a2ce1bc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_one", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master_local_tcp.json.in new file mode 100644 index 00000000000..2b476cfe546 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_master_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_MASTER@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_one", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_two", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_three", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x1111", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x2222", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x3333", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_one", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in new file mode 100644 index 00000000000..78defe5eca3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave.json.in @@ -0,0 +1,76 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing":"subscribe_notify_test_service_four", + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave_local_tcp.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave_local_tcp.json.in new file mode 100644 index 00000000000..0e076a122ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_same_client_ids_same_ports_slave_local_tcp.json.in @@ -0,0 +1,83 @@ +{ + "unicast":"@TEST_IP_SLAVE@", + "logging": + { + "level":"warning", + "console":"true", + "file": + { + "enable":"false", + "path":"/tmp/vsomeip.log" + }, + "dlt":"true" + }, + "applications": + [ + { + "name":"subscribe_notify_test_service_four", + "id":"0x1111" + }, + { + "name":"subscribe_notify_test_service_five", + "id":"0x2222" + }, + { + "name":"subscribe_notify_test_service_six", + "id":"0x3333" + } + ], + "services": + [ + { + "service":"0x4444", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x5555", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + }, + { + "service":"0x6666", + "instance":"0x0001", + "unreliable":"30000", + "reliable": + { + "port":"40000", + "enable-magic-cookies":"false" + } + } + ], + "routing": + { + "host" : + { + "name" : "subscribe_notify_test_service_four", + "unicast" : "127.0.0.1" + } + }, + "service-discovery": + { + "enable":"true", + "multicast":"224.0.0.1", + "port":"30490", + "protocol":"udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_slave_starter.sh.in new file mode 100755 index 00000000000..84b4010881b --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/conf/subscribe_notify_test_slave_starter.sh.in @@ -0,0 +1,56 @@ +#!/bin/bash +# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +if [ $# -lt 1 ] +then + echo "Please pass a json file to this script." + echo "For example: $0 UDP subscribe_notify_test_diff_client_ids_diff_ports_slave.json" + echo "To use the same service id but different instances on the node pass SAME_SERVICE_ID as third parameter" + exit 1 +fi + +RELIABILITY_TYPE=$1 +SLAVE_JSON_FILE=$2 +SAME_SERVICE_ID=$3 + +FAIL=0 + +# Start the services +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_four +export VSOMEIP_CONFIGURATION=$SLAVE_JSON_FILE +./subscribe_notify_test_service 4 $RELIABILITY_TYPE $3 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_five +export VSOMEIP_CONFIGURATION=$SLAVE_JSON_FILE +./subscribe_notify_test_service 5 $RELIABILITY_TYPE $3 & + +export VSOMEIP_APPLICATION_NAME=subscribe_notify_test_service_six +export VSOMEIP_CONFIGURATION=$SLAVE_JSON_FILE +./subscribe_notify_test_service 6 $RELIABILITY_TYPE $3 & + +sleep 3 + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_globals.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_globals.hpp new file mode 100644 index 00000000000..761c3c4bff3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_globals.hpp @@ -0,0 +1,55 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ +#define SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ + +namespace subscribe_notify_test { + +struct service_info { + vsomeip::service_t service_id; + vsomeip::instance_t instance_id; + vsomeip::method_t method_id; + vsomeip::event_t event_id; + vsomeip::eventgroup_t eventgroup_id; +}; + +static constexpr std::array<service_info, 7> service_infos = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 }, + { 0x2222, 0x1, 0x2222, 0x2222, 0x2000 }, + { 0x3333, 0x1, 0x3333, 0x3333, 0x3000 }, + // node 2 + { 0x4444, 0x1, 0x4444, 0x4444, 0x4000 }, + { 0x5555, 0x1, 0x5555, 0x5555, 0x5000 }, + { 0x6666, 0x1, 0x6666, 0x6666, 0x6000 } +}}; + +static constexpr std::array<service_info, 7> service_infos_same_service_id = {{ + // placeholder to be consistent w/ client ids, service ids, app names + { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }, + // node 1 + { 0x1111, 0x1, 0x1111, 0x1111, 0x1000 }, + { 0x1111, 0x2, 0x2222, 0x2222, 0x2000 }, + { 0x1111, 0x3, 0x3333, 0x3333, 0x3000 }, + // node 2 + { 0x2222, 0x1, 0x4444, 0x4444, 0x4000 }, + { 0x2222, 0x2, 0x5555, 0x5555, 0x5000 }, + { 0x2222, 0x3, 0x6666, 0x6666, 0x6000 } +}}; + +static constexpr int notifications_to_send = 10; + +// one_event_two_eventgroups globals +static constexpr struct service_info service_info_subscriber_based_notification = + { 0xCAFE, 0x1, 0x8888, 0x8111, 0x1}; +static constexpr vsomeip::method_t shutdown_method_id = 0x6666; +static constexpr vsomeip::method_t set_method_id = 0x7777; + +} + +#endif /* SUBSCRIBE_NOTIFY_TEST_GLOBALS_HPP_ */ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp new file mode 100644 index 00000000000..6b3ae294032 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_client.cpp @@ -0,0 +1,398 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <utility> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include <gtest/gtest.h> + +#include "subscribe_notify_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class subscribe_notify_test_one_event_two_eventgroups_client : public vsomeip_utilities::base_logger { +public: + subscribe_notify_test_one_event_two_eventgroups_client( + struct subscribe_notify_test::service_info _info, bool _use_tcp) : + vsomeip_utilities::base_logger("SNC1", "SUBSCRIBE NOTIFY TEST ONE EVENT TWO EVENTGROUPS CLIENT"), + app_( + vsomeip::runtime::get()->create_application( + "subscribe_notify_test_client")), + info_(_info), + use_tcp_(_use_tcp), + wait_availability_(true), + wait_set_value_(true), + wait_shutdown_response_(true), + run_thread_(std::bind(&subscribe_notify_test_one_event_two_eventgroups_client::run, this)) { + } + ~subscribe_notify_test_one_event_two_eventgroups_client() { + run_thread_.join(); + } + + bool init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + + app_->register_state_handler( + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_state, + this, std::placeholders::_1)); + + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_message, + this, std::placeholders::_1)); + + app_->register_availability_handler(info_.service_id, info_.instance_id, + std::bind( + &subscribe_notify_test_one_event_two_eventgroups_client::on_availability, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + std::set<vsomeip::eventgroup_t> its_groups; + // the service offers three events in two eventgroups + // one of the events is in both eventgroups (info_.event_id + 2) + its_groups.insert(info_.eventgroup_id); + app_->request_event(info_.service_id, info_.instance_id, + info_.event_id, its_groups, + vsomeip::event_type_e::ET_FIELD, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), + its_groups, vsomeip::event_type_e::ET_FIELD, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + its_groups.erase(info_.eventgroup_id); + its_groups.insert(static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id +1)); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id+1), + its_groups, vsomeip::event_type_e::ET_FIELD, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->request_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id+2), + its_groups, vsomeip::event_type_e::ET_FIELD, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + + return true; + } + + void start() { + app_->start(); + } + + void stop() { + app_->clear_all_handler(); + app_->unsubscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->unsubscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + app_->release_event(info_.service_id, info_.instance_id, info_.event_id); + app_->release_event(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id+1)); + app_->release_event(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id+2)); + app_->release_service(info_.service_id, info_.instance_id); + app_->stop(); + } + + void on_state(vsomeip::state_type_e _state) { + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(info_.service_id, info_.instance_id); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, + bool _is_available) { + VSOMEIP_DEBUG << "Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service + << "." << _instance << "] is " + << (_is_available ? "available." : "NOT available."); + if (_service == info_.service_id && _instance == info_.instance_id && _is_available) { + std::lock_guard<std::mutex> its_lock(availability_mutex_); + wait_availability_ = false; + availability_condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + std::stringstream its_message; + its_message << "Received a message [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_service() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_instance() << "." + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_method() << "] from Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _response->get_session() + << "] = "; + std::shared_ptr<vsomeip::payload> its_payload = + _response->get_payload(); + its_message << "(" << std::dec << its_payload->get_length() << ") "; + for (uint32_t i = 0; i < its_payload->get_length(); ++i) + its_message << std::hex << std::setw(2) << std::setfill('0') + << (int) its_payload->get_data()[i] << " "; + VSOMEIP_DEBUG << its_message.str(); + ASSERT_EQ(info_.service_id, _response->get_service()); + + if (_response->get_method() == info_.method_id + || _response->get_method() == subscribe_notify_test::shutdown_method_id) { + ASSERT_EQ(vsomeip::message_type_e::MT_RESPONSE, _response->get_message_type()); + ASSERT_EQ(vsomeip::return_code_e::E_OK, _response->get_return_code()); + std::lock_guard<std::mutex> its_lock(shutdown_response_mutex_); + wait_shutdown_response_ = false; + shutdown_response_condition_.notify_one(); + } else if (_response->get_method() == subscribe_notify_test::set_method_id) { + std::lock_guard<std::mutex> its_lock(set_value_mutex_); + wait_set_value_ = false; + set_value_condition_.notify_one(); + } else if (_response->get_method() >= info_.event_id + && _response->get_method() <= static_cast<vsomeip::event_t>(info_.event_id + 3)) { + std::lock_guard<std::mutex> its_lock(events_mutex_); + received_events_.push_back(_response->get_payload()); + if (received_events_.size() > 4) { + ADD_FAILURE() << "Received too many events [" + << std::hex << _response->get_method() + << " (" << std::dec << received_events_.size() << ")"; + } + number_received_events_[_response->get_method()]++; + events_condition_.notify_one(); + } else { + ADD_FAILURE() << "Received unknown method id: " << std::setw(4) + << std::setfill('0') << std::hex << _response->get_method(); + } + + } + + void set_field_at_service(vsomeip::byte_t _value) { + std::shared_ptr<vsomeip::runtime> its_runtime = vsomeip::runtime::get(); + std::shared_ptr<vsomeip::message> its_request = its_runtime->create_request(false); + its_request->set_service(info_.service_id); + its_request->set_instance(info_.instance_id); + its_request->set_method(subscribe_notify_test::set_method_id); + its_request->set_reliable(use_tcp_); + std::shared_ptr<vsomeip::payload> its_payload = its_runtime->create_payload(&_value, sizeof(_value)); + its_request->set_payload(its_payload); + app_->send(its_request); + } + + void call_method_at_service(vsomeip::method_t _method) { + std::shared_ptr<vsomeip::runtime> its_runtime = vsomeip::runtime::get(); + std::shared_ptr<vsomeip::message> its_request = its_runtime->create_request(false); + its_request->set_service(info_.service_id); + its_request->set_instance(info_.instance_id); + its_request->set_method(_method); + its_request->set_reliable(use_tcp_); + app_->send(its_request); + } + + void wait_on_condition(std::unique_lock<std::mutex>&& _lock, bool *_predicate, std::condition_variable&& _condition, std::uint32_t _timeout) { + while (*_predicate) { + if (std::cv_status::timeout == _condition.wait_for(_lock, std::chrono::seconds(_timeout))) { + ADD_FAILURE() << "Condition variable wasn't notified within time (" + << _timeout << "sec)"; + } + } + *_predicate = true; + } + + void subscribe_at_service() { + // subscribe to both eventgroups + app_->subscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->subscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + } + + void unsubscribe_at_service() { + app_->unsubscribe(info_.service_id, info_.instance_id, info_.eventgroup_id); + app_->unsubscribe(info_.service_id, info_.instance_id, static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id+1)); + } + + void wait_for_events(std::unique_lock<std::mutex>&& _lock, + std::uint32_t _expected_number_received_events, + std::condition_variable&& _condition) { + std::cv_status its_status(std::cv_status::no_timeout); + while (received_events_.size() != _expected_number_received_events + && its_status != std::cv_status::timeout) { + its_status = _condition.wait_for(_lock, std::chrono::seconds(15)); + if (std::cv_status::timeout == its_status) { + ADD_FAILURE() << "Didn't receive expected number of events: " + << _expected_number_received_events + << " within time. Instead received: " << received_events_.size(); + } + } + ASSERT_EQ(size_t(_expected_number_received_events), received_events_.size()); + } + + void check_received_events_payload(vsomeip::byte_t _value) { + for (const auto &p : received_events_) { + ASSERT_EQ(vsomeip::length_t(1), p->get_length()); + ASSERT_EQ(vsomeip::byte_t(_value), *p->get_data()); + } + received_events_.clear(); + } + + void check_received_events_number(std::set<std::pair<vsomeip::event_t, std::uint32_t>> _expected) { + for (const auto &e : _expected) { + auto event = number_received_events_.find(e.first); + ASSERT_NE(number_received_events_.end(), event); + ASSERT_EQ(e.second, event->second); + } + number_received_events_.clear(); + } + + void run() { + std::unique_lock<std::mutex> its_availability_lock(availability_mutex_); + wait_on_condition(std::move(its_availability_lock), &wait_availability_, std::move(availability_condition_), 300); + // service is available now + + for (int i = 0; i < 3; i++) { + // set value + set_field_at_service(0x1); + { + std::unique_lock<std::mutex> its_set_value_lock(set_value_mutex_); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_), 30); + } + + // subscribe + std::unique_lock<std::mutex> its_events_lock(events_mutex_); + subscribe_at_service(); + wait_for_events(std::move(its_events_lock), 4, std::move(events_condition_)); + check_received_events_payload(0x1); + + std::set<std::pair<vsomeip::event_t, std::uint32_t>> its_expected; + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + // Initial event for the event which is member of both eventgroups has to be sent twice + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 2}); + + check_received_events_number(its_expected); + its_expected.clear(); + // set value again + set_field_at_service(0x2); + { + std::unique_lock<std::mutex> its_set_value_lock(set_value_mutex_); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_), 30); + } + + wait_for_events(std::move(its_events_lock), 3, std::move(events_condition_)); + check_received_events_payload(0x2); + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 1}); + + check_received_events_number(its_expected); + its_expected.clear(); + + // set value again + set_field_at_service(0x3); + { + std::unique_lock<std::mutex> its_set_value_lock(set_value_mutex_); + wait_on_condition(std::move(its_set_value_lock), &wait_set_value_, std::move(set_value_condition_), 30); + } + wait_for_events(std::move(its_events_lock), 3, std::move(events_condition_)); + check_received_events_payload(0x3); + its_expected.insert({info_.event_id, 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+1), 1}); + its_expected.insert({static_cast<vsomeip::event_t>(info_.event_id+2), 1}); + check_received_events_number(its_expected); + + unsubscribe_at_service(); + // sleep some time to ensure the unsubscription was processed by the + // remote routing_manager before setting the field again in the next + // loop. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + std::unique_lock<std::mutex> its_shutdown_lock(shutdown_response_mutex_); + call_method_at_service(subscribe_notify_test::shutdown_method_id); + wait_on_condition(std::move(its_shutdown_lock), &wait_shutdown_response_, std::move(shutdown_response_condition_), 30); + stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + struct subscribe_notify_test::service_info info_; + bool use_tcp_; + + bool wait_availability_; + std::mutex availability_mutex_; + std::condition_variable availability_condition_; + + bool wait_set_value_; + std::mutex set_value_mutex_; + std::condition_variable set_value_condition_; + + bool wait_shutdown_response_; + std::mutex shutdown_response_mutex_; + std::condition_variable shutdown_response_condition_; + + std::mutex events_mutex_; + std::condition_variable events_condition_; + + std::vector<std::shared_ptr<vsomeip::payload>> received_events_; + std::map<vsomeip::event_t, std::uint32_t> number_received_events_; + std::thread run_thread_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + subscribe_notify_test_one_event_two_eventgroups_client *its_client_ptr(nullptr); + void handle_signal(int _signal) { + if (its_client_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_client_ptr->stop(); + } +#endif + +static bool use_tcp; + +TEST(someip_subscribe_notify_test_one_event_two_eventgroups, subscribe_to_service) +{ + subscribe_notify_test_one_event_two_eventgroups_client its_client( + subscribe_notify_test::service_info_subscriber_based_notification, use_tcp); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_client_ptr = &its_client; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_client.init()) { + its_client.start(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a offer type of the service, like: " << argv[0] << " UDP" << std::endl; + std::cerr << "Valid offer types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + if(std::string("TCP") == std::string(argv[1])) { + use_tcp = true; + } else if(std::string("UDP") == std::string(argv[1])) { + use_tcp = false; + } else { + std::cerr << "Wrong subscription type passed, exiting" << std::endl; + std::cerr << "Valid subscription types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp new file mode 100644 index 00000000000..2432732288a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_one_event_two_eventgroups_service.cpp @@ -0,0 +1,249 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING +#include <csignal> +#endif +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <atomic> + +#include <gtest/gtest.h> +#include <vsomeip/internal/logger.hpp> + +#include <vsomeip/vsomeip.hpp> + +#include "subscribe_notify_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class subscribe_notify_test_one_event_two_eventgroups_service : public vsomeip_utilities::base_logger { +public: + subscribe_notify_test_one_event_two_eventgroups_service(subscribe_notify_test::service_info _info, bool _use_tcp) : + vsomeip_utilities::base_logger("SNS1", "SUBSCRIBE NOTIFY TEST ONE EVENT TWO EVENTGROUPS SERVICE"), + app_(vsomeip::runtime::get()->create_application()), + wait_for_shutdown_(true), + info_(_info), + notify_thread_(std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::wait_for_shutdown, this)), + use_tcp_(_use_tcp) { + } + + ~subscribe_notify_test_one_event_two_eventgroups_service() { + notify_thread_.join(); + } + + bool init() { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return false; + } + app_->register_state_handler( + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_state, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + subscribe_notify_test::set_method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_set, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + info_.method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_message, this, + std::placeholders::_1)); + + app_->register_message_handler( + info_.service_id, + info_.instance_id, + subscribe_notify_test::shutdown_method_id, + std::bind(&subscribe_notify_test_one_event_two_eventgroups_service::on_shutdown, this, + std::placeholders::_1)); + + std::set<vsomeip::eventgroup_t> its_groups; + // the service offers three events in two eventgroups + // one of the events is in both eventgroups + its_groups.insert(info_.eventgroup_id); + app_->offer_event(info_.service_id, info_.instance_id, + info_.event_id, its_groups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), + its_groups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + its_groups.erase(info_.eventgroup_id); + its_groups.insert(static_cast<vsomeip::eventgroup_t>(info_.eventgroup_id + 1)); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 1), + its_groups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + app_->offer_event(info_.service_id, info_.instance_id, + static_cast<vsomeip::event_t>(info_.event_id + 2), + its_groups, vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), + false, true, nullptr, + (use_tcp_ ? vsomeip::reliability_type_e::RT_RELIABLE : vsomeip::reliability_type_e::RT_UNRELIABLE)); + payload_ = vsomeip::runtime::get()->create_payload(); + + return true; + } + + void start() { + app_->start(); + } + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + /* + * Handle signal to shutdown + */ + void stop() { + { + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + wait_for_shutdown_ = false; + shutdown_condition_.notify_one(); + } + app_->clear_all_handler(); + stop_offer(); + notify_thread_.join(); + app_->stop(); + } +#endif + + void offer() { + app_->offer_service(info_.service_id, info_.instance_id); + } + + void stop_offer() { + app_->stop_offer_service(info_.service_id, info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + std::cout << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered.") << std::endl; + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + offer(); + } + } + + void on_shutdown(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + its_response->set_payload(payload_); + app_->send(its_response); + { + std::lock_guard<std::mutex> its_lock(shutdown_mutex_); + wait_for_shutdown_ = false; + shutdown_condition_.notify_one(); + } + } + + void on_set(const std::shared_ptr<vsomeip::message> &_message) { + std::shared_ptr<vsomeip::message> its_response + = vsomeip::runtime::get()->create_response(_message); + payload_ = _message->get_payload(); + its_response->set_payload(payload_); + app_->send(its_response); + app_->notify(info_.service_id, info_.instance_id, info_.event_id, payload_); + app_->notify(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id + 1), payload_); + app_->notify(info_.service_id, info_.instance_id, static_cast<vsomeip::event_t>(info_.event_id + 2), payload_); + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + app_->send(vsomeip::runtime::get()->create_response(_message)); + } + + void wait_for_shutdown() { + { + std::unique_lock<std::mutex> its_lock(shutdown_mutex_); + while (wait_for_shutdown_) { + shutdown_condition_.wait(its_lock); + } + wait_for_shutdown_= true; + } + + app_->clear_all_handler(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + stop_offer(); + app_->stop(); + } + +private: + std::shared_ptr<vsomeip::application> app_; + + std::mutex shutdown_mutex_; + bool wait_for_shutdown_; + std::condition_variable shutdown_condition_; + + std::shared_ptr<vsomeip::payload> payload_; + + subscribe_notify_test::service_info info_; + + std::thread notify_thread_; + bool use_tcp_; +}; + +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + subscribe_notify_test_one_event_two_eventgroups_service *its_service_ptr(nullptr); + void handle_signal(int _signal) { + if (its_service_ptr != nullptr && + (_signal == SIGINT || _signal == SIGTERM)) + its_service_ptr->stop(); + } +#endif + +static bool use_tcp; + +TEST(someip_subscribe_notify_test_one_event_two_eventgroups, wait_for_attribute_set) +{ + subscribe_notify_test_one_event_two_eventgroups_service its_service( + subscribe_notify_test::service_info_subscriber_based_notification, use_tcp); +#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING + its_service_ptr = &its_service; + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); +#endif + if (its_service.init()) { + its_service.start(); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a offer type of the service, like: " << argv[0] << " UDP" << std::endl; + std::cerr << "Valid offer types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + if(std::string("TCP") == std::string(argv[1])) { + use_tcp = true; + } else if(std::string("UDP") == std::string(argv[1])) { + use_tcp = false; + } else { + std::cerr << "Wrong subscription type passed, exiting" << std::endl; + std::cerr << "Valid subscription types include:" << std::endl; + std::cerr << "[UDP, TCP]" << std::endl; + return 1; + } + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_service.cpp new file mode 100644 index 00000000000..c08d46f9a5e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/subscribe_notify_tests/subscribe_notify_test_service.cpp @@ -0,0 +1,517 @@ +// Copyright (C) 2014-2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <chrono> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <thread> +#include <map> +#include <algorithm> +#include <atomic> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "subscribe_notify_test_globals.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class subscribe_notify_test_service : public vsomeip_utilities::base_logger { +public: + subscribe_notify_test_service(struct subscribe_notify_test::service_info _service_info, + std::array<subscribe_notify_test::service_info, 7> _service_infos, + vsomeip::reliability_type_e _reliability_type) : + vsomeip_utilities::base_logger("SNTS", "SUBSCRIBE NOTIFY TEST SERVICE"), + service_info_(_service_info), + service_infos_(_service_infos), + app_(vsomeip::runtime::get()->create_application()), + wait_until_registered_(true), + wait_until_other_services_available_(true), + wait_until_notified_from_other_services_(true), + offer_thread_(std::bind(&subscribe_notify_test_service::run, this)), + wait_for_stop_(true), + stop_thread_(std::bind(&subscribe_notify_test_service::wait_for_stop, this)), + wait_for_notify_(true), + notify_thread_(std::bind(&subscribe_notify_test_service::notify, this)), + subscription_error_occured_(false), + reliability_type_(_reliability_type) { + if (!app_->init()) { + ADD_FAILURE() << "Couldn't initialize application"; + return; + } + + app_->register_state_handler( + std::bind(&subscribe_notify_test_service::on_state, this, + std::placeholders::_1)); + app_->register_message_handler(service_info_.service_id, + service_info_.instance_id, service_info_.method_id, + std::bind(&subscribe_notify_test_service::on_request, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&subscribe_notify_test_service::on_message, this, + std::placeholders::_1)); + + // offer event + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(service_info_.eventgroup_id); + app_->offer_event(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_eventgroups, + vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(), + false, true, nullptr, reliability_type_); + + + // register availability for all other services and request their event. + for(const auto& i : service_infos_) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + app_->request_service(i.service_id, i.instance_id); + app_->register_availability_handler(i.service_id, i.instance_id, + std::bind(&subscribe_notify_test_service::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + + auto handler = std::bind(&subscribe_notify_test_service::on_subscription_state_change, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); + app_->register_subscription_status_handler(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::ANY_EVENT, handler); + + + std::set<vsomeip::eventgroup_t> its_eventgroups; + its_eventgroups.insert(i.eventgroup_id); + app_->request_event(i.service_id, i.instance_id, i.event_id, its_eventgroups, + vsomeip::event_type_e::ET_FIELD, reliability_type_); + + other_services_available_[std::make_pair(i.service_id, i.instance_id)] = false; + other_services_received_notification_[std::make_pair(i.service_id, i.method_id)] = 0; + } + + // register subscription handler to detect whether or not all other + // other services have subscribed + app_->register_subscription_handler(service_info_.service_id, + service_info_.instance_id, service_info_.eventgroup_id, + std::bind(&subscribe_notify_test_service::on_subscription, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + + app_->start(); + } + + ~subscribe_notify_test_service() { + offer_thread_.join(); + stop_thread_.join(); + } + + void offer() { + app_->offer_service(service_info_.service_id, service_info_.instance_id); + } + + void stop_offer() { + app_->stop_offer_event(service_info_.service_id, service_info_.instance_id, service_info_.event_id); + app_->stop_offer_service(service_info_.service_id, service_info_.instance_id); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_registered_ = false; + } + condition_.notify_one(); + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + auto its_service = other_services_available_.find(std::make_pair(_service, _instance)); + if(its_service != other_services_available_.end()) { + if(its_service->second != _is_available) { + its_service->second = true; + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is available."; + + } + } + + if(std::all_of(other_services_available_.cbegin(), + other_services_available_.cend(), + [](const std::map<std::pair<vsomeip::service_t, + vsomeip::instance_t>, bool>::value_type& v) { + return v.second;})) { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_other_services_available_ = false; + } + condition_.notify_one(); + } + } + + void on_subscription_state_change(const vsomeip::service_t _service, const vsomeip::instance_t _instance, + const vsomeip::eventgroup_t _eventgroup, const vsomeip::event_t _event, const uint16_t _error) { + (void)_event; + + std::lock_guard<std::mutex> its_lock(subscription_state_handler_called_mutex_); + if (!_error) { + subscription_state_handler_called_.insert(std::make_tuple(_service, _instance, _eventgroup)); + } else { + subscription_error_occured_ = true; + VSOMEIP_WARNING << std::hex << app_->get_client() + << " : on_subscription_state_change: for service " << std::hex + << _service << " received a subscription error!"; + } + } + + bool on_subscription(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid, + bool _subscribed) { + (void)_uid; + (void)_gid; + std::lock_guard<std::mutex> its_lock(subscribers_mutex_); + static bool notified(false); + if (_subscribed) { + subscribers_.insert(_client); + } else { + subscribers_.erase(_client); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " << "Client: " + << std::setw(4) << std::setfill('0') << std::hex << _client + << (_subscribed ? " subscribed" : " unsubscribed") + << ", now have " << std::dec << subscribers_.size() + << " subscribers" ; + // check if all other services have subscribed: + // -1 for placeholder in array + // divide by two because we only receive once subscription per remote node + // no matter how many clients subscribed to this eventgroup on the remote node + if (!notified && subscribers_.size() == (service_infos_.size() - 1) / 2 ) + { + // notify the notify thread to start sending out notifications + std::lock_guard<std::mutex> its_lock(notify_mutex_); + wait_for_notify_ = false; + notified = true; + } + notify_condition_.notify_one(); + return true; + } + + void on_request(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_REQUEST) { + VSOMEIP_DEBUG << "Received a request with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "]"; + std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get() + ->create_response(_message); + app_->send(its_response); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + if(_message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) { + + other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())]++; + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " + << "Received a notification with Client/Session [" << std::setw(4) + << std::setfill('0') << std::hex << _message->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_session() << "] from Service/Method [" + << std::setw(4) << std::setfill('0') << std::hex + << _message->get_service() << "/" << std::setw(4) << std::setfill('0') + << std::hex << _message->get_method() << "/" << std::dec << _message->get_length() << "] (now have: " + << std::dec << other_services_received_notification_[std::make_pair(_message->get_service(), + _message->get_method())] << ")"; + + if(all_notifications_received()) { + std::lock_guard<std::mutex> its_lock(stop_mutex_); + wait_for_stop_ = false; + } + stop_condition_.notify_one(); + } + } + + bool all_notifications_received() { + return std::all_of( + other_services_received_notification_.cbegin(), + other_services_received_notification_.cend(), + [&](const std::map<std::pair<vsomeip::service_t, + vsomeip::method_t>, std::uint32_t>::value_type& v) + { + return v.second == subscribe_notify_test::notifications_to_send; + } + ); + } + + bool all_notifications_received_tcp_and_udp() { + std::uint32_t received_twice(0); + std::uint32_t received_normal(0); + for(const auto &v : other_services_received_notification_) { + if (v.second == subscribe_notify_test::notifications_to_send * 2) { + received_twice++; + } else if(v.second == subscribe_notify_test::notifications_to_send) { + received_normal++; + } + } + + if( received_twice == (service_infos_.size() - 1) / 2 + && received_normal == (service_infos_.size() - 1) / 2 - 1) { + // routing manager stub receives the notification + // - twice from external nodes + // - and normal from all internal nodes + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] " + << "Received notifications:" + << " Normal: " << received_normal + << " Twice: " << received_twice; + return true; + } + return false; + } + + void run() { + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Running"; + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_until_registered_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Offering"; + offer(); + + + while (wait_until_other_services_available_) { + condition_.wait(its_lock); + } + + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Subscribing"; + // subscribe to events of other services + uint32_t subscribe_count = 0; + for(const subscribe_notify_test::service_info& i: service_infos_) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + ++subscribe_count; + app_->subscribe(i.service_id, i.instance_id, i.eventgroup_id, + vsomeip::DEFAULT_MAJOR); + VSOMEIP_DEBUG << "[" << std::hex << service_info_.service_id + << "] subscribing to Service/Instance/Eventgroup [" + << std::setw(4) << std::setfill('0') << std::hex << i.service_id << "/" + << std::setw(4) << std::setfill('0') << std::hex << i.instance_id + << "/" << std::setw(4) << std::setfill('0') << std::hex << i.eventgroup_id << "]"; + } + + while (wait_until_notified_from_other_services_) { + condition_.wait(its_lock); + } + + // It is possible that we run in the case a subscription is NACKED + // due to TCP endpoint not completely connected when subscription + // is processed in the server - due to resubscribing the error handler + // count may differ from expected value, but its not a real but as + // the subscription takes places anyways and all events will be received. + std::lock_guard<std::mutex> its_subscription_lock(subscription_state_handler_called_mutex_); + if (!subscription_error_occured_) { + ASSERT_EQ(subscribe_count, subscription_state_handler_called_.size()); + } else { + VSOMEIP_WARNING << "Subscription state handler check skipped: CallCount=" + << std::dec << subscription_state_handler_called_.size(); + } + } + + void notify() { + std::unique_lock<std::mutex> its_lock(notify_mutex_); + while (wait_for_notify_) { + notify_condition_.wait(its_lock); + } + + // sleep a while before starting to notify this is necessary as it's not + // possible to detect if _all_ clients on the remote side have + // successfully subscribed as we only receive once subscription per + // remote node no matter how many clients subscribed to this eventgroup + // on the remote node + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Starting to notify"; + + for(uint32_t i = 0; i < subscribe_notify_test::notifications_to_send; i++) { + std::shared_ptr<vsomeip::payload> its_payload = + vsomeip::runtime::get()->create_payload(); + + vsomeip::byte_t its_data[10] = {0}; + for (uint32_t j = 0; j < i+1; ++j) { + its_data[j] = static_cast<uint8_t>(j); + } + its_payload->set_data(its_data, i+1); + VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id << "] Notifying: " << i+1; + app_->notify(service_info_.service_id, service_info_.instance_id, + service_info_.event_id, its_payload); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + + void wait_for_stop() { + std::unique_lock<std::mutex> its_lock(stop_mutex_); + while (wait_for_stop_) { + stop_condition_.wait(its_lock); + } + + // wait until all notifications have been sent out + notify_thread_.join(); + + VSOMEIP_INFO << "[" << std::setw(4) << std::setfill('0') << std::hex + << service_info_.service_id + << "] Received notifications from all other services, going down"; + + // let offer thread exit + { + std::lock_guard<std::mutex> its_lock(mutex_); + wait_until_notified_from_other_services_ = false; + } + condition_.notify_one(); + + stop_offer(); + + // ensure that the service which hosts the routing doesn't exit to early + if (app_->is_routing()) { + for (const auto& i : service_infos_) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + while (app_->is_available(i.service_id, i.instance_id, + vsomeip::ANY_MAJOR, vsomeip::ANY_MINOR)) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + for(const auto& i : service_infos_) { + if ((i.service_id == service_info_.service_id + && i.instance_id == service_info_.instance_id) + || (i.service_id == 0xFFFF && i.instance_id == 0xFFFF)) { + continue; + } + app_->unregister_subscription_status_handler(i.service_id, i.instance_id, + i.eventgroup_id, vsomeip::ANY_EVENT); + app_->unsubscribe(i.service_id, i.instance_id, i.eventgroup_id); + app_->release_event(i.service_id, i.instance_id, i.event_id); + app_->release_service(i.service_id, i.instance_id); + } + app_->clear_all_handler(); + app_->stop(); + } + +private: + subscribe_notify_test::service_info service_info_; + std::array<subscribe_notify_test::service_info, 7> service_infos_; + std::shared_ptr<vsomeip::application> app_; + std::map<std::pair<vsomeip::service_t, vsomeip::instance_t>, bool> other_services_available_; + std::map<std::pair<vsomeip::service_t, vsomeip::method_t>, std::uint32_t> other_services_received_notification_; + + bool wait_until_registered_; + bool wait_until_other_services_available_; + bool wait_until_notified_from_other_services_; + std::mutex mutex_; + std::condition_variable condition_; + std::thread offer_thread_; + + bool wait_for_stop_; + std::mutex stop_mutex_; + std::condition_variable stop_condition_; + std::thread stop_thread_; + + std::set<vsomeip::client_t> subscribers_; + bool wait_for_notify_; + std::mutex notify_mutex_; + std::condition_variable notify_condition_; + std::thread notify_thread_; + + std::mutex subscription_state_handler_called_mutex_; + bool subscription_error_occured_; + std::set<std::tuple<vsomeip::service_t, vsomeip::instance_t, + vsomeip::eventgroup_t> > subscription_state_handler_called_; + + std::mutex subscribers_mutex_; + vsomeip::reliability_type_e reliability_type_; +}; + +static unsigned long service_number; +static bool use_same_service_id; +vsomeip::reliability_type_e reliability_type = vsomeip::reliability_type_e::RT_UNKNOWN; + + +TEST(someip_subscribe_notify_test, send_ten_notifications_to_service) +{ + if(use_same_service_id) { + subscribe_notify_test_service its_sample( + subscribe_notify_test::service_infos_same_service_id[service_number], + subscribe_notify_test::service_infos_same_service_id, + reliability_type); + } else { + subscribe_notify_test_service its_sample( + subscribe_notify_test::service_infos[service_number], + subscribe_notify_test::service_infos, + reliability_type); + } +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + if(argc < 2) { + std::cerr << "Please specify a service number and event reliability type, like: " << argv[0] << " 2 UDP SAME_SERVICE_ID" << std::endl; + std::cerr << "Valid service numbers are in the range of [1,6]" << std::endl; + std::cerr << "Valid event reliability types are [UDP, TCP, TCP_AND_UDP]" << std::endl; + std::cerr << "If SAME_SERVICE_ID is specified as third parameter the test is run w/ multiple instances of the same service" << std::endl; + return 1; + } + + service_number = std::stoul(std::string(argv[1]), nullptr); + + if (argc >= 3) { + if (std::string("TCP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_RELIABLE; + } else if (std::string("UDP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_UNRELIABLE; + } else if (std::string("TCP_AND_UDP")== std::string(argv[2])) { + reliability_type = vsomeip::reliability_type_e::RT_BOTH; + } + } + + if (argc >= 4 && std::string("SAME_SERVICE_ID") == std::string(argv[3])) { + use_same_service_id = true; + } else { + use_same_service_id = false; + } + + + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/CMakeLists.txt new file mode 100644 index 00000000000..91d1d79e596 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (C) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +cmake_minimum_required(VERSION 3.4...3.22) + +project(suspend_resume_tests LANGUAGES CXX) + +# Configure necessary files into the build folder. +set(configuration_files + suspend_resume_test_client.json + suspend_resume_test_master_starter.sh + suspend_resume_test_service.json + suspend_resume_test_slave_starter.sh +) +configure_files("${configuration_files}") + +# Add test executable. +add_executable(suspend_resume_test_service + suspend_resume_test_service.cpp +) + +# Add test executable. +add_executable(suspend_resume_test_client + suspend_resume_test_client.cpp +) + +# Add build dependencies and link libraries to executables. +set(executables + suspend_resume_test_service + suspend_resume_test_client +) +targets_add_default_dependencies("${executables}") +targets_link_default_libraries("${executables}") + +# Add custom test command. +add_custom_test( + NAME suspend_resume_test_initial + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/suspend_resume_test_master_starter.sh SERVICE +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_client.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_client.json.in new file mode 100644 index 00000000000..352e4fdca8a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_client.json.in @@ -0,0 +1,32 @@ +{ + "unicast" : "@TEST_IP_SLAVE@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "suspend_resume_test_client", + "id" : "0x4567" + } + ], + "routing" : "suspend_resume_test_client", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_master_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_master_starter.sh.in new file mode 100755 index 00000000000..cc1c51c3773 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_master_starter.sh.in @@ -0,0 +1,72 @@ +#!/bin/bash +# Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Purpose: This script is needed to start the services with +# one command. This is necessary as ctest - which is used to run the +# tests - isn't able to start multiple binaries for one testcase. Therefore +# the testcase simply executes this script. This script then runs the services +# and checks that all exit successfully. + +FAIL=0 + +# Start the service +export VSOMEIP_APPLICATION_NAME=suspend_resume_test_service +export VSOMEIP_CONFIGURATION=suspend_resume_test_service.json + +# start daemon +echo -e "[TEST-sh]: Starting RoutingManager" +../../../examples/routingmanagerd/routingmanagerd & +PID_VSOMEIPD=$! + +# start the service +echo -e "\n\n[TEST-sh]: Started RoutingManager with PID=$PID_VSOMEIPD" +./suspend_resume_test_service $PID_VSOMEIPD & +PID_SERVICE=$! + +echo -e "\n\n[TEST-sh]: Started Service with PID=$PID_SERVICE \n\n" +sleep 1 + +if [ ! -z "$USE_LXC_TEST" ]; then + echo "starting suspend_resume_test_slave_starter.sh on slave LXC with parameters $SLAVE_JSON_FILE" + ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests/suspend_resume_tests; ./suspend_resume_test_slave_starter.sh\"" & + echo "remote ssh job id: $!" +elif [ ! -z "$USE_DOCKER" ]; then + docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./suspend_resume_test_slave_starter.sh" & +else + cat <<End-of-message +******************************************************************************* +******************************************************************************* +** Please now run: +** suspend_resume_test_slave_starter.sh +** from an external host to successfully complete this test. +** +** You probably will need to adapt the 'unicast' settings in +** suspend_resume_test_service.json and +** suspend_resume_test_client.json to your personal setup. +******************************************************************************* +******************************************************************************* +End-of-message +fi + +if [ ! -z "$USE_DOCKER" ]; then + FAIL=0 +fi + +# wait until client exits successfully +wait $PID_SERVICE || FAIL=$(($FAIL+1)) + +# kill daemon +kill $PID_VSOMEIPD +wait $PID_VSOMEIPD || FAIL=$(($FAIL+1)) + +echo "" + +# Check if both exited successfully +if [ $FAIL -eq 0 ]; then + exit 0 +else + exit 1 +fi \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_service.json.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_service.json.in new file mode 100644 index 00000000000..582740c6cdc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_service.json.in @@ -0,0 +1,40 @@ +{ + "unicast" : "@TEST_IP_MASTER@", + "netmask" : "255.255.255.0", + "logging" : + { + "level" : "debug", + "console" : "true", + "file" : { "enable" : "false", "path" : "" }, + "dlt" : "true" + }, + "applications" : + [ + { + "name" : "suspend_resume_test_service", + "id" : "0x7654" + } + ], + "services" : + [ + { + "service" : "0x6311", + "instance" : "0x0002", + "unreliable" : "34504" + } + ], + "routing" : "routingmanagerd", + "service-discovery" : + { + "enable" : "true", + "multicast" : "224.0.0.1", + "port" : "30490", + "protocol" : "udp", + "initial_delay_min" : "10", + "initial_delay_max" : "10", + "repetitions_base_delay" : "30", + "repetitions_max" : "3", + "cyclic_offer_delay" : "1000", + "ttl" : "3" + } +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_slave_starter.sh.in b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_slave_starter.sh.in new file mode 100755 index 00000000000..dbbbbb8cbe6 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/conf/suspend_resume_test_slave_starter.sh.in @@ -0,0 +1,29 @@ +#!/bin/bash +# Copyright (C) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FAIL=0 + +# Start the client +export VSOMEIP_APPLICATION_NAME=suspend_resume_test_client +export VSOMEIP_CONFIGURATION=suspend_resume_test_client.json +./suspend_resume_test_client & +PID_CLIENT=$! + +# Wait until all applications are finished +for job in $(jobs -p) +do + # Fail gets incremented if one of the binaries exits + # with a non-zero exit code + wait $job || ((FAIL+=1)) +done + +# Check if both exited successfully +if [ $FAIL -eq 0 ] +then + exit 0 +else + exit 1 +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test.hpp new file mode 100644 index 00000000000..7eae22399bc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SUSPEND_RESUME_TEST_ +#define SUSPEND_RESUME_TEST_ + +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +#define TEST_SERVICE 0x6311 +#define TEST_INSTANCE 0x0002 +#define TEST_MAJOR 0x01 +#define TEST_MINOR 0x0 + +#define TEST_EVENT 0x8005 +#define TEST_EVENTGROUP 0x0002 + +#define TEST_METHOD 0x0001 + +#define TEST_SUSPEND 0x00 +#define TEST_STOP 0xFF + +#endif // SUSPEND_RESUME_TEST_ diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_client.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_client.cpp new file mode 100644 index 00000000000..092a01f8df1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_client.cpp @@ -0,0 +1,253 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <condition_variable> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "suspend_resume_test.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +class suspend_resume_test_client : public vsomeip_utilities::base_logger { +public: + suspend_resume_test_client() + : vsomeip_utilities::base_logger("SRTC", "SUSPEND RESUME TEST CLIENT"), + name_("suspend_resume_test_client"), + app_(vsomeip::runtime::get()->create_application(name_)), + has_received_(false), + runner_(std::bind(&suspend_resume_test_client::run, this)) { + + } + + void run_test() { + + register_state_handler(); + register_message_handler(); + register_availability_handler(); + + start(); + + { + VSOMEIP_DEBUG << "Started."; + std::unique_lock<std::mutex> its_lock(mutex_); + auto r = cv_.wait_for(its_lock, std::chrono::seconds(10)); + VSOMEIP_DEBUG << "[TEST-cli] App Started: r=" << static_cast<int>(r); + EXPECT_EQ(r, std::cv_status::no_timeout); + } + + toggle(); + + { + VSOMEIP_DEBUG << "Toggled."; + std::unique_lock<std::mutex> its_lock(mutex_); + if (!has_received_) { + auto r = cv_.wait_for(its_lock, std::chrono::seconds(10)); + VSOMEIP_DEBUG << "[TEST-cli] First Receive Validation: r=" << static_cast<int>(r); + EXPECT_EQ(r, std::cv_status::no_timeout); + } else { + VSOMEIP_DEBUG << "[TEST-cli] Jumped received validation"; + } + } + + VSOMEIP_DEBUG << "[TEST-cli] Sending suspend/resume: "; + send_suspend(); + + bool was_successful; + { + VSOMEIP_DEBUG << "Triggered suspend/resume."; + // Wait for service to become availaber after suspend/resume. + std::unique_lock<std::mutex> its_lock(mutex_); + auto r = cv_.wait_for(its_lock, std::chrono::seconds(10)); + VSOMEIP_DEBUG << "[TEST-cli] Service Available after susp/resume: r=" << static_cast<int>(r); + EXPECT_EQ(r, std::cv_status::no_timeout); + + // Wait for initial event after suspend/resume. + r = cv_.wait_for(its_lock, std::chrono::seconds(10)); + VSOMEIP_DEBUG << "[TEST-cli] After susp/resume event validation: r=" << static_cast<int>(r); + EXPECT_EQ(r, std::cv_status::no_timeout); + + was_successful = (r == std::cv_status::no_timeout); + } + + if (was_successful) + send_stop(); + + stop(); + } + +private: + void register_state_handler() { + + app_->register_state_handler( + std::bind(&suspend_resume_test_client::on_state, this, std::placeholders::_1)); + } + + void register_availability_handler() { + + app_->register_availability_handler(TEST_SERVICE, TEST_INSTANCE, + std::bind(&suspend_resume_test_client::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + } + + void register_message_handler() { + + app_->register_message_handler(TEST_SERVICE, TEST_INSTANCE, TEST_EVENT, + std::bind(&suspend_resume_test_client::on_message, this, + std::placeholders::_1)); + } + + void start() { + + app_->init(); + cv_.notify_one(); + } + + void run() { + + { + std::unique_lock<std::mutex> its_lock(mutex_); + cv_.wait(its_lock); + } + + app_->start(); + } + + void stop() { + + app_->stop(); + runner_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + + VSOMEIP_DEBUG << __func__ << ": state=" + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "NOT registered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_event(TEST_SERVICE, TEST_INSTANCE, TEST_EVENT, { TEST_EVENTGROUP }); + app_->request_service(TEST_SERVICE, TEST_INSTANCE); + } + } + + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + + static bool is_available(false); + + if (_service == TEST_SERVICE && _instance == TEST_INSTANCE) { + + VSOMEIP_DEBUG << __func__ << ": Test service is " + << (_is_available ? "available." : "NOT available."); + + if (_is_available) { + VSOMEIP_DEBUG << "[TEST-cli] On availability will trigger cv"; + cv_.notify_one(); + } else if (is_available) { + VSOMEIP_DEBUG << "[TEST-cli] On availability=false, clearing has_received"; + has_received_ = false; + } + is_available = _is_available; + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + + if (_message->get_service() == TEST_SERVICE + && _message->get_instance() == TEST_INSTANCE + && _message->get_method() == TEST_EVENT) { + + VSOMEIP_DEBUG << __func__ << ": Received event."; + if (!has_received_) { + has_received_ = true; + VSOMEIP_DEBUG << "[TEST-cli] HasReceived Changed, triggering cv"; + cv_.notify_one(); + } + } + } + + void toggle() { + VSOMEIP_DEBUG << "[TEST-cli] Toggle Start"; + app_->subscribe(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP, TEST_MAJOR); + std::this_thread::sleep_for(std::chrono::seconds(3)); + VSOMEIP_DEBUG << "[TEST-cli] Toggle Middle"; + app_->unsubscribe(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP); + app_->subscribe(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP, TEST_MAJOR); + std::this_thread::sleep_for(std::chrono::seconds(2)); + app_->unsubscribe(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP); + app_->subscribe(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP, TEST_MAJOR); + VSOMEIP_DEBUG << "[TEST-cli] Toggle End"; + } + + + void send_suspend() { + + auto its_message = vsomeip::runtime::get()->create_request(false); + its_message->set_service(TEST_SERVICE); + its_message->set_instance(TEST_INSTANCE); + its_message->set_method(TEST_METHOD); + its_message->set_interface_version(TEST_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_return_code(vsomeip::return_code_e::E_OK); + + vsomeip::byte_t its_data[] = { TEST_SUSPEND }; + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(its_data, sizeof(its_data)); + its_message->set_payload(its_payload); + + app_->send(its_message); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + + void send_stop() { + + auto its_message = vsomeip::runtime::get()->create_request(false); + its_message->set_service(TEST_SERVICE); + its_message->set_instance(TEST_INSTANCE); + its_message->set_method(TEST_METHOD); + its_message->set_interface_version(TEST_MAJOR); + its_message->set_message_type(vsomeip::message_type_e::MT_REQUEST_NO_RETURN); + its_message->set_return_code(vsomeip::return_code_e::E_OK); + + vsomeip::byte_t its_data[] = { TEST_STOP }; + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(its_data, sizeof(its_data)); + its_message->set_payload(its_payload); + + app_->send(its_message); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + +private: // members + std::string name_; + std::shared_ptr<vsomeip::application> app_; + std::mutex mutex_; + std::condition_variable cv_; + bool has_received_; + std::thread runner_; +}; + +TEST(suspend_resume_test, fast) +{ + suspend_resume_test_client its_client; + its_client.run_test(); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + VSOMEIP_DEBUG << "[TEST-cli] Starting Client"; + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_service.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_service.cpp new file mode 100644 index 00000000000..68a1c829c99 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/network_tests/suspend_resume_tests/suspend_resume_test_service.cpp @@ -0,0 +1,217 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <atomic> +#include <condition_variable> +#include <iomanip> +#include <mutex> +#include <thread> + +#include <gtest/gtest.h> + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "suspend_resume_test.hpp" +#include "../someip_test_globals.hpp" +#include <common/vsomeip_app_utilities.hpp> + +pid_t daemon_pid__; + +class suspend_resume_test_service : public vsomeip_utilities::base_logger { +public: + suspend_resume_test_service() + : vsomeip_utilities::base_logger("ATCA", "APPLICATION TEST CLIENT AVAILABILITY"), + name_("suspend_resume_test_service"), + app_(vsomeip::runtime::get()->create_application(name_)), + is_running_(true), + is_unblocked_(false), + runner_(std::bind(&suspend_resume_test_service::run, this)), + sr_runner_(std::bind(&suspend_resume_test_service::sr_run, this)) { + } + + void run_test() { + + register_state_handler(); + register_message_handler(); + register_subscription_handler(); + + start(); + + VSOMEIP_DEBUG << "Using daemon with pid=" << std::dec << daemon_pid__; + + { + std::unique_lock<std::mutex> its_lock(mutex_); + auto r = cv_.wait_for(its_lock, std::chrono::seconds(30)); + EXPECT_EQ(r, std::cv_status::no_timeout); + } + + stop(); + } + +private: + void start() { + + app_->init(); + cv_.notify_one(); + } + + void stop() { + + is_running_ = false; + sr_cv_.notify_one(); + + app_->stop(); + + runner_.join(); + sr_runner_.join(); + } + + void run() { + + { + std::unique_lock<std::mutex> its_lock(mutex_); + cv_.wait(its_lock); + } + + app_->start(); + } + + void sr_run() { + + while (is_running_) { + std::unique_lock<std::mutex> its_lock(sr_mutex_); + sr_cv_.wait(its_lock); + + if (is_running_) { + VSOMEIP_DEBUG << "send kill SIGUSR1 to PID: " << std::dec << daemon_pid__; + kill(daemon_pid__, SIGUSR1); + std::this_thread::sleep_for(std::chrono::seconds(5)); + VSOMEIP_DEBUG << "send kill SIGUSR2 to PID: " << std::dec << daemon_pid__; + kill(daemon_pid__, SIGUSR2); + } + } + } + + void register_state_handler() { + + app_->register_state_handler( + std::bind(&suspend_resume_test_service::on_state, this, std::placeholders::_1)); + } + + void register_message_handler() { + + app_->register_message_handler(TEST_SERVICE, TEST_INSTANCE, TEST_METHOD, + std::bind(&suspend_resume_test_service::on_message, this, + std::placeholders::_1)); + } + + void register_subscription_handler() { + + app_->register_subscription_handler(TEST_SERVICE, TEST_INSTANCE, TEST_EVENTGROUP, + std::bind(&suspend_resume_test_service::on_subscribe, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + } + + void offer_service() { + app_->offer_event(TEST_SERVICE, TEST_INSTANCE, TEST_EVENT, { TEST_EVENTGROUP }, + vsomeip::event_type_e::ET_FIELD, + std::chrono::milliseconds::zero(), false, true, nullptr, + vsomeip::reliability_type_e::RT_UNRELIABLE); + + vsomeip::byte_t its_data[] = { 0x1, 0x2, 0x3 }; + auto its_payload = vsomeip::runtime::get()->create_payload(); + its_payload->set_data(its_data, sizeof(its_data)); + app_->notify(TEST_SERVICE, TEST_INSTANCE, TEST_EVENT, its_payload); + + app_->offer_service(TEST_SERVICE, TEST_INSTANCE, TEST_MAJOR, TEST_MINOR); + } + + // handler + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_DEBUG << __func__ << "[TEST-srv]: state=" + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "NOT registered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + offer_service(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_message) { + + VSOMEIP_DEBUG << __func__ << "[TEST-srv]: Received " + << std::hex << std::setw(4) << std::setfill('0') + << _message->get_service() + << std::hex << std::setw(4) << std::setfill('0') + << _message->get_instance() + << std::hex << std::setw(4) << std::setfill('0') + << _message->get_method(); + + if (_message->get_service() == TEST_SERVICE + && _message->get_instance() == TEST_INSTANCE + && _message->get_method() == TEST_METHOD) { + + if (_message->get_payload()->get_length() == 1) { + + vsomeip::byte_t its_control_byte(*_message->get_payload()->get_data()); + + switch (its_control_byte) { + case TEST_SUSPEND: + sr_cv_.notify_one(); + break; + case TEST_STOP: + cv_.notify_one(); + break; + default: + ; + } + } + } + } + + bool on_subscribe(vsomeip::client_t _client, + vsomeip::uid_t _uid, vsomeip::gid_t _gid, + bool _is_subscribe) { + + (void)_client; + (void)_uid; + (void)_gid; + + VSOMEIP_DEBUG << __func__ << "[TEST-srv]: is_subscribe=" << std::boolalpha << _is_subscribe; + if (!_is_subscribe) + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + return true; + } + +private: // members + std::string name_; + std::shared_ptr<vsomeip::application> app_; + std::atomic<bool> is_running_; + bool is_unblocked_; + std::mutex mutex_; + std::condition_variable cv_; + std::mutex sr_mutex_; + std::condition_variable sr_cv_; + std::thread runner_; + std::thread sr_runner_; +}; + +TEST(suspend_resume_test, fast) +{ + suspend_resume_test_service its_service; + its_service.run_test(); +} + +#if defined(__linux__) || defined(ANDROID) || defined(__QNX__) +int main(int argc, char** argv) { + + ::testing::InitGoogleTest(&argc, argv); + + daemon_pid__ = atoi(argv[1]); + + return RUN_ALL_TESTS(); +} +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/tsan-suppressions.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/tsan-suppressions.txt new file mode 100644 index 00000000000..7c9fddd83dc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/tsan-suppressions.txt @@ -0,0 +1 @@ +mutex:libdlt.so \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/CMakeLists.txt new file mode 100644 index 00000000000..2dfca14b66c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_bin" LANGUAGES CXX) + +add_subdirectory(message_payload_impl_tests) +add_subdirectory(message_serializer_tests) +add_subdirectory(message_deserializer_tests) +add_subdirectory(protocol_tests) +add_subdirectory(routing_manager_tests) +add_subdirectory(security_policy_manager_impl_tests) +add_subdirectory(security_policy_tests) +add_subdirectory(security_tests) +add_subdirectory(utility_utility_tests) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/main.cpp new file mode 100644 index 00000000000..00ed93a6539 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/main.cpp @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/CMakeLists.txt new file mode 100644 index 00000000000..caebfe9dada --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_message_deserializer_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + Threads::Threads + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/ut_deserialize.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/ut_deserialize.cpp new file mode 100644 index 00000000000..c33d0b408f3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_deserializer_tests/ut_deserialize.cpp @@ -0,0 +1,530 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <vsomeip/primitive_types.hpp> + +#include "../../../implementation/message/include/deserializer.hpp" +#include "../../../implementation/utility/include/bithelper.hpp" + +namespace { + constexpr std::uint32_t buffer_shrink_threshold = 1; + constexpr std::uint8_t array_size = 4; + const vsomeip_v3::byte_t byte1 = 1; + const vsomeip_v3::byte_t byte2 = 2; + const vsomeip_v3::byte_t byte3 = 3; + const vsomeip_v3::byte_t byte4 = 4; + const bool omit_last_byte = true; + const bool dont_omit_last_byte = false; +} + +TEST(deserialize_test, deserialize_get_available) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Testing the correct array size is returned. + ASSERT_EQ(its_deserializer->get_available(), array_size); + ASSERT_EQ(its_deserializer->get_available(), its_deserializer->get_remaining()); +} + +TEST(deserialize_test, deserialize_set_get_remaining) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Testing the correct remaining length is returned after every step. + vsomeip_v3::byte_t deserialized_byte_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(its_deserializer->get_remaining(), 3); + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(its_deserializer->get_remaining(), 2); + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(its_deserializer->get_remaining(), 1); + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(its_deserializer->get_remaining(), 0); + + // Setting the remaining size to array size to test setter. + its_deserializer->set_remaining(array_size); + ASSERT_EQ(its_deserializer->get_remaining(), array_size); + ASSERT_NE(its_deserializer->get_remaining(), 0); +} + +TEST(deserialize_test, deserialize_from_uint8) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Deserialize data 1 byte (uint8_t) at a time and check against expected value. + vsomeip_v3::byte_t deserialized_byte_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte1); + ASSERT_NE(deserialized_byte_, byte4); + + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte2); + ASSERT_NE(deserialized_byte_, byte3); + + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte3); + ASSERT_NE(deserialized_byte_, byte2); + + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte4); + ASSERT_NE(deserialized_byte_, byte1); +} + +TEST(deserialize_test, deserialize_from_uint16) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + // Create arrays to use with bithelper. + std::array<vsomeip_v3::byte_t, 2> uint16_array_1_{byte1, byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_2_{byte3, byte4}; + + // Creating two uint16_t with the data from the byte_array. + std::uint16_t uint16_1 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_1_.data()); + std::uint16_t uint16_2 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_2_.data()); + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Deserialize 2 uint16_t from the data, and compare them with their expected values. + std::uint16_t deserialized_uint16_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_uint16_)); + ASSERT_EQ(deserialized_uint16_, uint16_1); + ASSERT_NE(deserialized_uint16_, uint16_2); + + ASSERT_TRUE(its_deserializer->deserialize(deserialized_uint16_)); + ASSERT_EQ(deserialized_uint16_, uint16_2); + ASSERT_NE(deserialized_uint16_, uint16_1); +} + +TEST(deserialize_test, deserialize_from_uint32_omit_last_byte) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_3_bytes_array_{0, byte1, byte2, byte3}; + std::array<vsomeip_v3::byte_t, 4> uint32_full_array_{byte1, byte2, byte3, byte4}; + + // Create two uint32_t from the data, one including 3 bytes and the other with the full 4 bytes + const std::uint32_t uint32_3_bytes = vsomeip_v3::bithelper::read_uint32_be(uint32_3_bytes_array_.data()); + const std::uint32_t uint32_full = vsomeip_v3::bithelper::read_uint32_be(uint32_full_array_.data()); + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Deserialize a uint32_t omitting the last byte + std::uint32_t deserialized_uint32_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_uint32_, omit_last_byte)); + ASSERT_EQ(deserialized_uint32_, uint32_3_bytes); + ASSERT_NE(deserialized_uint32_, uint32_full); +} + +TEST(deserialize_test, deserialize_from_uint32_dont_omit_last_byte) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_3_bytes_array_{0, byte1, byte2, byte3}; + std::array<vsomeip_v3::byte_t, 4> uint32_full_array_{byte1, byte2, byte3, byte4}; + + // Create two uint32_t from the data, one including 3 bytes and the other with the full 4 bytes + const std::uint32_t uint32_3_bytes = vsomeip_v3::bithelper::read_uint32_be(uint32_3_bytes_array_.data()); + const std::uint32_t uint32_full = vsomeip_v3::bithelper::read_uint32_be(uint32_full_array_.data()); + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Deserialize a full uint32_t not omitting the last byte. + std::uint32_t deserialized_uint32_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_uint32_, dont_omit_last_byte)); + ASSERT_EQ(deserialized_uint32_, uint32_full); + ASSERT_NE(deserialized_uint32_, uint32_3_bytes); +} + +TEST(deserialize_test, deserialize_from_uint8_array_pointer_and_length) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // One shot deserialization of the full data. + std::array<vsomeip_v3::byte_t, array_size> deserialized_byte_array_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_array_.data(), deserialized_byte_array_.size())); + + // Check deserialized data for endianness and expected values. + ASSERT_EQ(deserialized_byte_array_.at(0), byte1); + ASSERT_EQ(deserialized_byte_array_.at(1), byte2); + ASSERT_EQ(deserialized_byte_array_.at(2), byte3); + ASSERT_EQ(deserialized_byte_array_.at(3), byte4); + ASSERT_NE(deserialized_byte_array_.at(0), byte4); + ASSERT_NE(deserialized_byte_array_.at(1), byte3); + ASSERT_NE(deserialized_byte_array_.at(2), byte2); + ASSERT_NE(deserialized_byte_array_.at(3), byte1); + + // Attempt a second try with a step by step deserialization. + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Check deserialized data for endianness and expected values. + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_byte_array_.data(), 2)); + ASSERT_EQ(deserialized_byte_array_.at(0), byte1); + ASSERT_EQ(deserialized_byte_array_.at(1), byte2); + ASSERT_NE(deserialized_byte_array_.at(0), byte2); + ASSERT_NE(deserialized_byte_array_.at(1), byte1); + + // Check deserialized data against expected and old values. + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_byte_array_.data(), 2)); + ASSERT_EQ(deserialized_byte_array_.at(0), byte3); + ASSERT_EQ(deserialized_byte_array_.at(1), byte4); + ASSERT_NE(deserialized_byte_array_.at(0), byte1); + ASSERT_NE(deserialized_byte_array_.at(1), byte2); +} + +TEST(deserialize_test, deserialize_from_string_pointer_and_length) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // One shot deserialization of the full data. + std::string deserialized_string_ = "0000"; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_string_, array_size)); + + // Check deserialized data for endianness and expected values. + ASSERT_EQ(deserialized_string_[0], byte1); + ASSERT_EQ(deserialized_string_[1], byte2); + ASSERT_EQ(deserialized_string_[2], byte3); + ASSERT_EQ(deserialized_string_[3], byte4); + ASSERT_NE(deserialized_string_[0], byte4); + ASSERT_NE(deserialized_string_[1], byte3); + ASSERT_NE(deserialized_string_[2], byte2); + ASSERT_NE(deserialized_string_[3], byte1); + + // Attempt a second try with a step by step deserialization. + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_string_, 2)); + + // Check deserialized data for endianness and expected values. + ASSERT_EQ(deserialized_string_[0], byte1); + ASSERT_EQ(deserialized_string_[1], byte2); + ASSERT_NE(deserialized_string_[0], byte2); + ASSERT_NE(deserialized_string_[1], byte1); + + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_string_, 2)); + + // Check deserialized data against expected and old values. + ASSERT_EQ(deserialized_string_[0], byte3); + ASSERT_EQ(deserialized_string_[1], byte4); + ASSERT_NE(deserialized_string_[0], byte1); + ASSERT_NE(deserialized_string_[1], byte2); + +} + +TEST(deserialize_test, deserialize_from_uint8_t_vector) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // One shot deserialization of the full data. Creating a vector with size 4 + std::vector<std::uint8_t> deserialized_vector_(4); + + ASSERT_TRUE(its_deserializer->deserialize(deserialized_vector_)); + + // Check deserialized data for endianness and expected values. + ASSERT_EQ(deserialized_vector_.at(0), byte1); + ASSERT_EQ(deserialized_vector_.at(1), byte2); + ASSERT_EQ(deserialized_vector_.at(2), byte3); + ASSERT_EQ(deserialized_vector_.at(3), byte4); + ASSERT_NE(deserialized_vector_.at(0), byte4); + ASSERT_NE(deserialized_vector_.at(1), byte3); + ASSERT_NE(deserialized_vector_.at(2), byte2); + ASSERT_NE(deserialized_vector_.at(3), byte1); + + // Attempt a second try with a step by step deserialization. + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Creating a size 2 vector + std::vector<std::uint8_t> deserialized_vector2_(2); + + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_vector2_)); + + // Check deserialized data for endianness and expected values. + ASSERT_EQ(deserialized_vector2_.at(0), byte1); + ASSERT_EQ(deserialized_vector2_.at(1), byte2); + ASSERT_NE(deserialized_vector2_.at(0), byte2); + ASSERT_NE(deserialized_vector2_.at(1), byte1); + + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_vector2_)); + + // Check deserialized data against expected and old values. + ASSERT_EQ(deserialized_vector2_.at(0), byte3); + ASSERT_EQ(deserialized_vector2_.at(1), byte4); + ASSERT_NE(deserialized_vector2_.at(0), byte1); + ASSERT_NE(deserialized_vector2_.at(1), byte2); +} + +TEST(deserialize_test, look_ahead_for_uint8) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // look_ahead data 1 byte (uint8_t) at a time and check against expected value. + vsomeip_v3::byte_t look_ahead_byte_; + ASSERT_TRUE(its_deserializer->look_ahead(0, look_ahead_byte_)); + ASSERT_EQ(look_ahead_byte_, byte1); + ASSERT_NE(look_ahead_byte_, byte4); + + ASSERT_TRUE(its_deserializer->look_ahead(1, look_ahead_byte_)); + ASSERT_EQ(look_ahead_byte_, byte2); + ASSERT_NE(look_ahead_byte_, byte3); + + ASSERT_TRUE(its_deserializer->look_ahead(2, look_ahead_byte_)); + ASSERT_EQ(look_ahead_byte_, byte3); + ASSERT_NE(look_ahead_byte_, byte2); + + ASSERT_TRUE(its_deserializer->look_ahead(3, look_ahead_byte_)); + ASSERT_EQ(look_ahead_byte_, byte4); + ASSERT_NE(look_ahead_byte_, byte1); +} + +TEST(deserialize_test, look_ahead_for_uint16) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + // Creating the three possible uint16_t with the data from the byte_array + + // Create arrays to use with bithelper. + std::array<vsomeip_v3::byte_t, 2> uint16_array_1_{byte1, byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_2_{byte2, byte3}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_3_{byte3, byte4}; + + // Creating two uint16_t with the data from the byte_array. + std::uint16_t uint16_1 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_1_.data()); + std::uint16_t uint16_2 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_2_.data()); + std::uint16_t uint16_3 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_3_.data()); + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Look_ahead uint16_t from incrementing indices and compare them with their expected values. + std::uint16_t look_ahead_uint16_; + ASSERT_TRUE(its_deserializer->look_ahead(0, look_ahead_uint16_)); + ASSERT_EQ(look_ahead_uint16_, uint16_1); + ASSERT_NE(look_ahead_uint16_, uint16_2); + + ASSERT_TRUE(its_deserializer->look_ahead(1, look_ahead_uint16_)); + ASSERT_EQ(look_ahead_uint16_, uint16_2); + ASSERT_NE(look_ahead_uint16_, uint16_1); + + ASSERT_TRUE(its_deserializer->look_ahead(2, look_ahead_uint16_)); + ASSERT_EQ(look_ahead_uint16_, uint16_3); + ASSERT_NE(look_ahead_uint16_, uint16_1); +} + +TEST(deserialize_test, look_ahead_for_uint32) { + // Extend array size + std::array<vsomeip_v3::byte_t, array_size+1> byte_array_{byte1, byte2, byte3, byte4, byte1}; + + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_1_bytes_array_{byte1, byte2, byte3, byte4}; + std::array<vsomeip_v3::byte_t, 4> uint32_2_bytes_array_{byte2, byte3, byte4, byte1}; + + // Creating the uint32_t with the data from the byte_array + const std::uint32_t uint32_1 = vsomeip_v3::bithelper::read_uint32_be(uint32_1_bytes_array_.data()); + const std::uint32_t uint32_2 = vsomeip_v3::bithelper::read_uint32_be(uint32_2_bytes_array_.data()); + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Look_ahead uint32_t from incrementing indices and compare them with their expected values. + std::uint32_t look_ahead_uint32_; + ASSERT_TRUE(its_deserializer->look_ahead(0, look_ahead_uint32_)); + ASSERT_EQ(look_ahead_uint32_, uint32_1); + ASSERT_NE(look_ahead_uint32_, uint32_2); + + ASSERT_TRUE(its_deserializer->look_ahead(1, look_ahead_uint32_)); + ASSERT_EQ(look_ahead_uint32_, uint32_2); + ASSERT_NE(look_ahead_uint32_, uint32_1); +} + +TEST(deserialize_test, deserialize_message) { + // Extend array size to the size of a message without options + // the 8 is the length of the header needs to be atleast 8 to offset the header length + // the last bytes are all 0 to reflect uint32_t length + std::array<vsomeip_v3::byte_t, 25> byte_array_{ + byte1, byte2, byte3, byte4, 0, + 0, 0, 8, byte4, byte1, + byte1, byte2, byte3, byte4, byte1, + byte1, byte2, byte3, byte4, byte1, + 0, 0, 0, 0, 0}; + + // Deserialize expected to pass. + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + auto deserialized_message = its_deserializer->deserialize_message(); + ASSERT_NE(deserialized_message, nullptr); + + std::array<vsomeip_v3::byte_t, array_size> byte_array2_{byte1, byte2, byte3, byte4}; + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array2_.data(), byte_array2_.size(), buffer_shrink_threshold)); + + auto deserialized_message2 = its_deserializer2->deserialize_message(); + + // Desereialize expected to fail. + ASSERT_EQ(deserialized_message2, nullptr); +} + +TEST(deserialize_test, set_data_from_uint8_array_pointer_and_length) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Reversing the byte_array_ + std::array<vsomeip_v3::byte_t, array_size> reverse_byte_array_{byte4, byte3, byte2, byte1}; + + // Test Method + its_deserializer->set_data(reverse_byte_array_.data(), reverse_byte_array_.size()); + + // One shot deserialization of the full data. + std::array<vsomeip_v3::byte_t, array_size> deserialized_byte_array_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_array_.data(), deserialized_byte_array_.size())); + + // Check deserialized data expected values. + ASSERT_EQ(deserialized_byte_array_.at(0), byte4); + ASSERT_EQ(deserialized_byte_array_.at(1), byte3); + ASSERT_EQ(deserialized_byte_array_.at(2), byte2); + ASSERT_EQ(deserialized_byte_array_.at(3), byte1); + + // Attempt a second try with null array expect data to get cleared and remaining to be 0 + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + its_deserializer2->set_data(nullptr, array_size); + + // Remaining should have been set to 0 and the data cleared. + ASSERT_EQ(its_deserializer2->get_remaining(), 0); + + // Check deserialize failure. + ASSERT_FALSE(its_deserializer2->deserialize(deserialized_byte_array_.data(), deserialized_byte_array_.size())); +} + +TEST(deserialize_test, set_data_from_uint8_vector) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // One shot deserialization of the full data. Creating a vector with size 4 + std::vector<std::uint8_t> uint8_vector_{byte4, byte3, byte2, byte1, byte4}; + + // Test Method + its_deserializer->set_data(uint8_vector_); + + // Remaining size should be array_size + 1 + ASSERT_EQ(its_deserializer->get_remaining(), array_size + 1); + + // One shot deserialization of the full data. + std::array<vsomeip_v3::byte_t, array_size + 1> deserialized_byte_array_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_array_.data(), deserialized_byte_array_.size())); + + // Check deserialized data expected values. + ASSERT_EQ(deserialized_byte_array_.at(0), byte4); + ASSERT_EQ(deserialized_byte_array_.at(1), byte3); + ASSERT_EQ(deserialized_byte_array_.at(2), byte2); + ASSERT_EQ(deserialized_byte_array_.at(3), byte1); + ASSERT_EQ(deserialized_byte_array_.at(4), byte4); +} + +TEST(deserialize_test, append_data_from_uint8_array_pointer_and_length) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Reversing the byte_array_ + std::array<vsomeip_v3::byte_t, array_size> reverse_byte_array_{byte4, byte3, byte2, byte1}; + + // Test Method + its_deserializer->append_data(reverse_byte_array_.data(), reverse_byte_array_.size()); + + // Test remaining is twice the array length after appending + ASSERT_EQ(its_deserializer->get_remaining(), array_size * 2); + + // One shot deserialization of the full data. + std::array<vsomeip_v3::byte_t, array_size * 2> deserialized_byte_array_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_array_.data(), deserialized_byte_array_.size())); + + // Check deserialized data expected values. + ASSERT_EQ(deserialized_byte_array_.at(0), deserialized_byte_array_.at(7)); + ASSERT_EQ(deserialized_byte_array_.at(1), deserialized_byte_array_.at(6)); + ASSERT_EQ(deserialized_byte_array_.at(2), deserialized_byte_array_.at(5)); + ASSERT_EQ(deserialized_byte_array_.at(3), deserialized_byte_array_.at(4)); +} + +TEST(deserialize_test, drop_data) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Test Method. + its_deserializer->drop_data(1); + + // Deserialize 1 byte expect to get byte2 since we dropped byte1. + vsomeip_v3::byte_t deserialized_byte_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte2); + ASSERT_NE(deserialized_byte_, byte1); + + // Test Method. + its_deserializer->drop_data(1); + + // Deserialize 1 byte expect to get byte4 since we dropped byte3. + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte4); + ASSERT_NE(deserialized_byte_, byte3); + + // New deserializer to jump 3 spots instead of just 1 + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer2( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Test Method. + its_deserializer2->drop_data(3); + + // Deserialize 1 byte expect to get byte4 since we dropped byte1 - byte3. + ASSERT_TRUE(its_deserializer2->deserialize(deserialized_byte_)); + ASSERT_EQ(deserialized_byte_, byte4); + ASSERT_NE(deserialized_byte_, byte1); +} + +TEST(deserialize_test, reset) { + std::array<vsomeip_v3::byte_t, array_size> byte_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::deserializer> its_deserializer( + new vsomeip_v3::deserializer(byte_array_.data(), byte_array_.size(), buffer_shrink_threshold)); + + // Deserialize 1 byte expect to get byte2 since we dropped byte1. + vsomeip_v3::byte_t deserialized_byte_; + ASSERT_TRUE(its_deserializer->deserialize(deserialized_byte_)); + + // Expect remaining size to be 1 less than array size, since we read 1 byte. + ASSERT_EQ(its_deserializer->get_remaining(), array_size - 1); + + // Test Method. + its_deserializer->reset(); + + // Expect the size to be 0 since the data vector is now empty. + ASSERT_EQ(its_deserializer->get_remaining(), 0); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/CMakeLists.txt new file mode 100644 index 00000000000..aeea25cb2e0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_message_payload_impl_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/ut_payload_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/ut_payload_impl.cpp new file mode 100644 index 00000000000..fc6a14b411e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_payload_impl_tests/ut_payload_impl.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include "../../../implementation/message/include/deserializer.hpp" +#include "../../../implementation/message/include/payload_impl.hpp" +#include "../../../implementation/message/include/serializer.hpp" + +namespace { + const std::uint8_t array_size = 4; + const std::uint32_t buffer_shrink_threshold = 1; + const vsomeip_v3::byte_t byte1 = 1; + const vsomeip_v3::byte_t byte2 = 2; + const vsomeip_v3::byte_t byte3 = 3; + const vsomeip_v3::byte_t byte4 = 4; + +} + +TEST(payload_impl_test, equalequal_operator) { + // Create test data. + std::vector<std::uint8_t> data_vector_{byte1, byte2, byte3, byte4}; + + vsomeip_v3::payload_impl its_payload_impl(data_vector_); + + std::vector<std::uint8_t> data_vector2_{byte1, byte2, byte3, byte4}; + + vsomeip_v3::payload_impl its_similar_payload_impl(data_vector2_); + + std::vector<std::uint8_t> data_vector3_{byte4, byte3, byte2, byte1}; + + vsomeip_v3::payload_impl its_different_payload_impl(data_vector3_); + + // Checks. + ASSERT_TRUE(its_payload_impl == its_similar_payload_impl); + ASSERT_FALSE(its_payload_impl == its_different_payload_impl); +} + +TEST(payload_impl_test, set_data) { + // Create test data. + std::vector<vsomeip_v3::byte_t> data_vector_{byte1, byte2, byte3, byte4}; + + std::array<std::uint8_t, array_size> data_array_{byte1, byte2, byte3, byte4}; + + vsomeip_v3::payload_impl its_payload_impl1; + vsomeip_v3::payload_impl its_payload_impl2; + vsomeip_v3::payload_impl its_payload_impl3; + + // Test methods. + its_payload_impl1.set_data(data_vector_); + its_payload_impl2.set_data(data_array_.data(), data_array_.size()); + its_payload_impl3.set_data(std::move(data_vector_)); + + // Checks. + ASSERT_TRUE(its_payload_impl1 == its_payload_impl2); + ASSERT_TRUE(its_payload_impl1 == its_payload_impl3); +} + +TEST(payload_impl_test, constructors) { + // Create test data. + std::vector<std::uint8_t> data_vector_{byte1, byte2, byte3, byte4}; + + std::array<std::uint8_t, array_size> data_array_{byte1, byte2, byte3, byte4}; + + // Test Overloaded constructors. + vsomeip_v3::payload_impl its_payload_impl1; + // Add data to the empty data. + its_payload_impl1.set_data(data_vector_); + + vsomeip_v3::payload_impl its_payload_impl2(data_vector_); + vsomeip_v3::payload_impl its_payload_impl3(data_array_.data(), data_array_.size()); + vsomeip_v3::payload_impl its_payload_impl4(its_payload_impl1); + + // Checks. + ASSERT_TRUE(its_payload_impl1 == its_payload_impl2); + ASSERT_TRUE(its_payload_impl1 == its_payload_impl3); + ASSERT_TRUE(its_payload_impl1 == its_payload_impl4); +} + +TEST(payload_impl_test, get_length) { + // Create test data. + std::array<std::uint8_t, array_size> data_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::payload_impl> its_payload_impl(new vsomeip_v3::payload_impl(data_array_.data(), data_array_.size())); + + // Test method. + ASSERT_EQ(its_payload_impl->get_length(), array_size); +} + +TEST(payload_impl_test, serialize) { + // Create test data. + std::array<std::uint8_t, array_size> data_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::payload_impl> its_payload_impl(new vsomeip_v3::payload_impl(data_array_.data(), data_array_.size())); + vsomeip_v3::serializer its_serializer(buffer_shrink_threshold); + + // Test method. + ASSERT_TRUE(its_payload_impl->serialize(&its_serializer)); + + // Checks. + ASSERT_EQ(its_payload_impl->get_data()[0], its_serializer.get_data()[0]); + ASSERT_EQ(its_payload_impl->get_data()[1], its_serializer.get_data()[1]); + ASSERT_EQ(its_payload_impl->get_data()[2], its_serializer.get_data()[2]); + ASSERT_EQ(its_payload_impl->get_data()[3], its_serializer.get_data()[3]); +} + +TEST(payload_impl_test, deserialize) { + // Create test data. + std::array<std::uint8_t, array_size> data_array_{byte1, byte2, byte3, byte4}; + + std::unique_ptr<vsomeip_v3::payload_impl> its_payload_impl(new vsomeip_v3::payload_impl()); + vsomeip_v3::deserializer its_deserializer(data_array_.data(), data_array_.size(), buffer_shrink_threshold); + + // Test set_capacity at the same time. + its_payload_impl->set_capacity(array_size); + + // Test Method. + ASSERT_TRUE(its_payload_impl->deserialize(&its_deserializer)); + + // Checks. + ASSERT_EQ(its_payload_impl->get_length(), array_size); + ASSERT_EQ(its_payload_impl->get_data()[0], data_array_[0]); + ASSERT_EQ(its_payload_impl->get_data()[1], data_array_[1]); + ASSERT_EQ(its_payload_impl->get_data()[2], data_array_[2]); + ASSERT_EQ(its_payload_impl->get_data()[3], data_array_[3]); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/CMakeLists.txt new file mode 100644 index 00000000000..1fdb76c8817 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_message_serializer_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/ut_serialize.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/ut_serialize.cpp new file mode 100644 index 00000000000..5fd1eea1729 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/message_serializer_tests/ut_serialize.cpp @@ -0,0 +1,192 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include "../../../implementation/message/include/payload_impl.hpp" +#include "../../../implementation/message/include/serializer.hpp" +#include "../../../implementation/utility/include/bithelper.hpp" + +namespace { + const std::uint8_t uint8_num1= 1; + const std::uint8_t uint8_num2 = 2; + const std::uint8_t uint8_num3 = 3; + const std::uint16_t uint16_num1= 1; + const std::uint16_t uint16_num2 = 2; + const std::uint16_t uint16_num3 = 3; + const std::uint32_t uint32_num1= 1; + const std::uint32_t uint32_num2 = 2; + const std::uint32_t uint32_num3 = 3; + + bool omit_last_byte = true; + bool dont_omit_last_byte = false; +} + +TEST(serialize_test, serialize_from_serializable_pointer) { + std::vector<vsomeip_v3::byte_t> data_vector_{uint8_num1, uint8_num2, uint8_num3, uint8_num1}; + + auto its_serializable = new vsomeip_v3::payload_impl(data_vector_); + + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + ASSERT_TRUE(its_serializer->serialize(its_serializable)); + ASSERT_EQ(its_serializer->get_size(), 4); +} + + +TEST(serialize_test, serialize_from_uint8) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + //add 1 2 3 to the data of the serializer. + ASSERT_TRUE(its_serializer->serialize(uint8_num1)); + ASSERT_TRUE(its_serializer->serialize(uint8_num2)); + ASSERT_TRUE(its_serializer->serialize(uint8_num3)); + + ASSERT_EQ(its_serializer->get_data()[0], uint8_num1); + ASSERT_EQ(its_serializer->get_data()[1], uint8_num2); + ASSERT_EQ(its_serializer->get_data()[2], uint8_num3); + + ASSERT_EQ(its_serializer->get_size(), 3); +} + +TEST(serialize_test, serialize_from_uint16) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + //add 1 2 3 to the data of the serializer. + ASSERT_TRUE(its_serializer->serialize(uint16_num1)); + ASSERT_TRUE(its_serializer->serialize(uint16_num2)); + ASSERT_TRUE(its_serializer->serialize(uint16_num3)); + + // Rebuilding the uint16_t from 2 uint8_t words. + std::array<vsomeip_v3::byte_t, 2> uint16_array_reconstructed_num1_{its_serializer->get_data()[0], its_serializer->get_data()[1]}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_reconstructed_num2_{its_serializer->get_data()[2], its_serializer->get_data()[3]}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_reconstructed_num3_{its_serializer->get_data()[4], its_serializer->get_data()[5]}; + + std::uint16_t reconstructed_num1 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_reconstructed_num1_.data()); + std::uint16_t reconstructed_num2 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_reconstructed_num2_.data()); + std::uint16_t reconstructed_num3 = vsomeip_v3::bithelper::read_uint16_be(uint16_array_reconstructed_num3_.data()); + + ASSERT_EQ(reconstructed_num1, uint16_num1); + ASSERT_EQ(reconstructed_num2, uint16_num2); + ASSERT_EQ(reconstructed_num3, uint16_num3); + + ASSERT_EQ(its_serializer->get_size(), 6); +} + +TEST(serialize_test, serialize_from_uint32_omit_last_byte) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + //add 1 2 3 to the data of the serializer. + ASSERT_TRUE(its_serializer->serialize(uint32_num1, omit_last_byte)); + ASSERT_TRUE(its_serializer->serialize(uint32_num2, omit_last_byte)); + ASSERT_TRUE(its_serializer->serialize(uint32_num3, omit_last_byte)); + + // Rebuilding the uint32_t from 3 uint8_t words, since 4th byte is omited. + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num1_{0, its_serializer->get_data()[0], its_serializer->get_data()[1], its_serializer->get_data()[2]}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num2_{0, its_serializer->get_data()[3], its_serializer->get_data()[4], its_serializer->get_data()[5]}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num3_{0, its_serializer->get_data()[6], its_serializer->get_data()[7], its_serializer->get_data()[8]}; + + // Create uint32_t from bytes. + const std::uint32_t reconstructed_num1 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num1_.data()); + const std::uint32_t reconstructed_num2 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num2_.data()); + const std::uint32_t reconstructed_num3 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num3_.data()); + + ASSERT_EQ(reconstructed_num1, uint32_num1); + ASSERT_EQ(reconstructed_num2, uint32_num2); + ASSERT_EQ(reconstructed_num3, uint32_num3); + + ASSERT_EQ(its_serializer->get_size(), 9); +} + +TEST(serialize_test, serialize_from_uint32_dont_omit_last_byte) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + //add 1 2 3 to the data of the serializer. + ASSERT_TRUE(its_serializer->serialize(uint32_num1, dont_omit_last_byte)); + ASSERT_TRUE(its_serializer->serialize(uint32_num2, dont_omit_last_byte)); + ASSERT_TRUE(its_serializer->serialize(uint32_num3, dont_omit_last_byte)); + + // Rebuilding the uint32_t from 4 uint8_t words. + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num1_{its_serializer->get_data()[0], its_serializer->get_data()[1], its_serializer->get_data()[2], its_serializer->get_data()[3]}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num2_{its_serializer->get_data()[4], its_serializer->get_data()[5], its_serializer->get_data()[6], its_serializer->get_data()[7]}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_reconstructed_num3_{its_serializer->get_data()[8], its_serializer->get_data()[9], its_serializer->get_data()[10], its_serializer->get_data()[11]}; + + // Create uint32_t from bytes. + const std::uint32_t reconstructed_num1 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num1_.data()); + const std::uint32_t reconstructed_num2 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num2_.data()); + const std::uint32_t reconstructed_num3 = vsomeip_v3::bithelper::read_uint32_be(uint32_array_reconstructed_num3_.data()); + + ASSERT_EQ(reconstructed_num1, uint32_num1); + ASSERT_EQ(reconstructed_num2, uint32_num2); + ASSERT_EQ(reconstructed_num3, uint32_num3); + + ASSERT_EQ(its_serializer->get_size(), 12); +} + +TEST(serialize_test, serialize_from_uint8_array_with_length) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + std::vector<std::uint8_t> data_{uint8_num1, uint8_num2, uint8_num3}; + + ASSERT_TRUE(its_serializer->serialize(data_.data(), static_cast<std::uint32_t>(data_.size()))); + + ASSERT_EQ(its_serializer->get_data()[0], uint8_num1); + ASSERT_EQ(its_serializer->get_data()[1], uint8_num2); + ASSERT_EQ(its_serializer->get_data()[2], uint8_num3); + + ASSERT_EQ(its_serializer->get_size(), 3); +} + +TEST(serialize_test, serializer_get_capacity) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + ASSERT_GT(its_serializer->get_capacity(), 0); +} + +TEST(serialize_test, serializer_get_size) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + ASSERT_EQ(its_serializer->get_size(), 0); + ASSERT_TRUE(its_serializer->serialize(uint8_num1)); + ASSERT_EQ(its_serializer->get_size(), 1); + ASSERT_TRUE(its_serializer->serialize(uint8_num2)); + ASSERT_EQ(its_serializer->get_size(), 2); + ASSERT_TRUE(its_serializer->serialize(uint8_num3)); + ASSERT_EQ(its_serializer->get_size(), 3); +} + +TEST(serialize_test, serializer_reset) { + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + ASSERT_EQ(its_serializer->get_size(), 0); + ASSERT_TRUE(its_serializer->serialize(uint8_num1)); + ASSERT_TRUE(its_serializer->serialize(uint8_num2)); + ASSERT_TRUE(its_serializer->serialize(uint8_num3)); + ASSERT_EQ(its_serializer->get_size(), 3); + + its_serializer->reset(); + ASSERT_EQ(its_serializer->get_size(), 0); +} + +TEST(serialize_test, serializer_reset_shrink) { + //Not sure how this is supposed to go. + std::unique_ptr<vsomeip_v3::serializer> its_serializer(new vsomeip_v3::serializer(1)); + + ASSERT_TRUE(its_serializer->serialize(uint8_num1)); + ASSERT_TRUE(its_serializer->serialize(uint8_num2)); + ASSERT_TRUE(its_serializer->serialize(uint8_num3)); + ASSERT_EQ(its_serializer->get_size(), 3); + + its_serializer->reset(); + + ASSERT_TRUE(its_serializer->serialize(uint8_num1)); + ASSERT_TRUE(its_serializer->serialize(uint8_num2)); + ASSERT_TRUE(its_serializer->serialize(uint8_num3)); + ASSERT_EQ(its_serializer->get_size(), 3); + + its_serializer->reset(); + ASSERT_EQ(its_serializer->get_size(), 0); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/CMakeLists.txt new file mode 100644 index 00000000000..0bb739dbe09 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_protocol_tests" LANGUAGES CXX) + +file(GLOB TEST_SRCS main.cpp *.cpp) + +# We need to set the source files directly because vsomeip doesn't export the +# commands for linking. +set( + VSIP_SRCS + ../../../implementation/protocol/src/config_command.cpp + ../../../implementation/protocol/src/command.cpp +) + +add_executable( + ${PROJECT_NAME} + ${TEST_SRCS} + ${VSIP_SRCS} +) + +target_link_libraries( + ${PROJECT_NAME} + gtest +) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) + +add_test( + NAME ${PROJECT_NAME} + COMMAND ${PROJECT_NAME} +) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/main.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/main.cpp new file mode 100644 index 00000000000..531b4f65634 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/ut_config_command.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/ut_config_command.cpp new file mode 100644 index 00000000000..392fc7b8645 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/protocol_tests/ut_config_command.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include "../../../implementation/protocol/include/config_command.hpp" +#include "../../../implementation/protocol/include/protocol.hpp" + +namespace config_command_tests { + +// Tester Note: Expect Little-Endian representation for serialized data. +const std::vector<std::uint8_t> serialized_config_command = { + 0x31, // config_command + 0x00, 0x00, // Version. + 0x01, 0x00, // Client. + 0x20, 0x00, 0x00, 0x00, // Size. + // Configurations. + 0x04, 0x00, 0x00, 0x00, // Key size. + 0x61, 0x62, 0x63, 0x64, // "abcd" + 0x04, 0x00, 0x00, 0x00, // Value size. + 0x31, 0x32, 0x33, 0x34, // "1234" + 0x04, 0x00, 0x00, 0x00, // Key size. + 0x65, 0x66, 0x67, 0x68, // "efgh" + 0x04, 0x00, 0x00, 0x00, // Value size. + 0x35, 0x36, 0x37, 0x38 // "5678" +}; + +TEST(config_command_test, accessors) { + vsomeip_v3::protocol::config_command command; + ASSERT_FALSE(command.contains("abcd")); + command.insert("abcd", "1234"); + ASSERT_TRUE(command.contains("abcd")); + ASSERT_EQ(command.at("abcd"), "1234"); +} + +TEST(config_command_test, serialize) { + vsomeip_v3::protocol::config_command command; + command.set_client(0x0001); + command.insert("abcd", "1234"); + command.insert("efgh", "5678"); + + std::vector<std::uint8_t> buffer; + vsomeip_v3::protocol::error_e error; + command.serialize(buffer, error); + ASSERT_EQ(error, vsomeip_v3::protocol::error_e::ERROR_OK); + ASSERT_EQ(buffer, serialized_config_command); +} + +TEST(config_command_test, deserialize) { + vsomeip_v3::protocol::config_command command; + vsomeip_v3::protocol::error_e error; + command.deserialize(serialized_config_command, error); + ASSERT_EQ(error, vsomeip_v3::protocol::error_e::ERROR_OK); + ASSERT_EQ(command.configs().size(), 2); + EXPECT_EQ(command.configs().at("abcd"), "1234"); + EXPECT_EQ(command.configs().at("efgh"), "5678"); +} + +} // namespace config_command_tests diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/CMakeLists.txt new file mode 100644 index 00000000000..b650ddbcaba --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_routing_manager_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp mocks/*.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + Threads::Threads + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + gmock + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/mocks/mock_routing_manager_host.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/mocks/mock_routing_manager_host.hpp new file mode 100644 index 00000000000..3ff83996bfa --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/mocks/mock_routing_manager_host.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gmock/gmock.h> +#include "../../../../implementation/routing/include/routing_manager_host.hpp" + +using namespace vsomeip_v3; +class mock_routing_manager_host : public routing_manager_host { +public: + + MOCK_METHOD(client_t, get_client, (), (const, override)); + MOCK_METHOD(void, set_client, (const client_t &_client), (override)); + MOCK_METHOD(session_t, get_session, (bool _is_request), (override)); + + MOCK_METHOD(const vsomeip_sec_client_t* ,get_sec_client, (), (const, override)); + MOCK_METHOD(void, set_sec_client_port, (port_t _port), (override)); + + MOCK_METHOD(const std::string &, get_name, (), (const, override)); + MOCK_METHOD(std::shared_ptr<configuration>, get_configuration, (), (const, override)); + MOCK_METHOD(boost::asio::io_context &, get_io, (), (override)); + + MOCK_METHOD(void, on_availability, (service_t _service, instance_t _instance, + availability_state_e _state, + major_version_t _major, + minor_version_t _minor), (override)); + MOCK_METHOD(void, on_state, (state_type_e _state), (override)); + MOCK_METHOD(void, on_message, (std::shared_ptr<message> &&_message), (override)); + MOCK_METHOD(void, on_subscription, (service_t _service, instance_t _instance, + eventgroup_t _eventgroup, + client_t _client, const vsomeip_sec_client_t *_sec_client, + const std::string &_env, bool _subscribed, + const std::function<void(bool)> &_accepted_cb), (override)); + MOCK_METHOD(void, on_subscription_status, (service_t _service, instance_t _instance, + eventgroup_t _eventgroup, event_t _event, uint16_t _error), (override)); + MOCK_METHOD(void, send, (std::shared_ptr<message> _message), (override)); + MOCK_METHOD(void, on_offered_services_info, ( + (std::vector<std::pair<vsomeip_v3::service_t, vsomeip_v3::instance_t>>& _services)), (override)); + MOCK_METHOD(bool, is_routing, (), (const, override)); + +}; diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.cpp new file mode 100644 index 00000000000..324d99006ac --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "routing_manager_ut_setup.hpp" + +using ::testing::ReturnRef; +using ::testing::Return; + +void routing_manager_ut_setup::SetUp() { + configuration_ptr_ = + std::make_shared<vsomeip_v3::cfg::configuration_impl>("routing_manager_ut_config.json"); + + EXPECT_CALL(mock_host_, get_io()).WillRepeatedly(ReturnRef(io_)); + EXPECT_CALL(mock_host_, get_name()).WillRepeatedly(ReturnRef(name_)); + EXPECT_CALL(mock_host_, get_configuration()).WillRepeatedly(Return(configuration_ptr_)); + + // Create a test routing manager impl, with mock_host for routing_manager_host. + its_manager = new vsomeip_v3::routing_manager_impl(&mock_host_); + + its_manager->init(); +} + +void routing_manager_ut_setup::TearDown() { + delete its_manager; + configuration_ptr_.reset(); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.hpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.hpp new file mode 100644 index 00000000000..a3e110e8b08 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/routing_manager_ut_setup.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef ROUTING_MANAGER_UT_SETUP_HPP +#define ROUTING_MANAGER_UT_SETUP_HPP + +#include <boost/asio.hpp> +#include <boost/asio/io_context.hpp> +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <common/utility.hpp> + +#include "mocks/mock_routing_manager_host.hpp" + +class routing_manager_ut_setup : public testing::Test{ +protected : + mock_routing_manager_host mock_host_; + vsomeip_v3::routing_manager_impl* its_manager; + const std::string name_ = "RandomName"; + boost::asio::io_service io_; + std::shared_ptr<vsomeip_v3::cfg::configuration_impl> configuration_ptr_; + void SetUp() override; + // Tears down the test fixture. + void TearDown() override; +}; + +#endif // ROUTING_MANAGER_UT_SETUP_HPP diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/ut_set_routing_state.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/ut_set_routing_state.cpp new file mode 100644 index 00000000000..8426fa2b8cf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/routing_manager_tests/ut_set_routing_state.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "routing_manager_ut_setup.hpp" + +using ::testing::ReturnRef; +using ::testing::Return; +using ::testing::AtLeast; +using ::testing::_; + +namespace { + vsomeip_v3::service_t service_ = 0x1234; + vsomeip_v3::instance_t instance_ = 0x5678; + vsomeip_v3::service_t service2_ = 0x123; + vsomeip_v3::instance_t instance2_ = 0x567; + vsomeip_v3::major_version_t major_version_ = 1; + vsomeip_v3::minor_version_t minor_version_ = 1; + vsomeip_v3::ttl_t ttl_ = 3; + boost::asio::detail::array<unsigned char, 4> ip_bytes_= { 127, 0, 0, 1 }; + boost::asio::ip::address_v4 ip_address_(ip_bytes_); + boost::asio::detail::array<unsigned char, 4> ip_bytes_remote_= { 0xDE, 0xAD, 0xBE, 0xEF }; + boost::asio::ip::address_v4 ip_address_remote_(ip_bytes_remote_); + std::uint16_t port_reliable = 3506; + std::uint16_t port_unreliable = 3507; +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_SUSPENDED) { + + // Called on mock_host_ as a result of routing_manager_impl::del_routing_info being called within the logic tree + EXPECT_CALL(mock_host_, on_availability(_,_,_,_,_)).Times(AtLeast(1)); + + // Adding a service using add_routing_info this is a local service probably need to add remotes for this test + its_manager->add_routing_info(service_, instance_, major_version_, minor_version_, + ttl_, ip_address_, port_reliable, ip_address_, port_unreliable); + + // remote for on avail to be called as part of the del_routing_info call + its_manager->add_routing_info(service2_, instance2_, major_version_, minor_version_, + ttl_, ip_address_remote_, port_reliable, ip_address_remote_, port_unreliable); + + // Check it was added + auto service_list = its_manager->get_offered_services(); + ASSERT_TRUE(service_list.size() > 0); + + // Call test method with test input. + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_SUSPENDED); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_SUSPENDED); +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_RUNNING) { + + // Adding a service using add_routing_info + its_manager->add_routing_info(service_, instance_, major_version_, minor_version_, + ttl_, ip_address_, port_reliable, ip_address_, port_unreliable); + + // Check it was added + auto service_list = its_manager->get_offered_services(); + ASSERT_TRUE(service_list.size() > 0); + + // RS_RUNNING is the default value so set RS_SUSPENDED back to RS_RUNNING + // This is needed because the method exits right away if there is no state change. + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_SUSPENDED); + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_RUNNING); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_RUNNING); + + for (const auto &its_service : its_manager->get_offered_services()) { + for (const auto &its_instance : its_service.second) { + ASSERT_EQ(its_instance.second->get_ttl(), DEFAULT_TTL); + ASSERT_FALSE(its_instance.second->is_in_mainphase()); + } + } +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_RESUMED) { + + // Adding a service using add_routing_info + its_manager->add_routing_info(service_, instance_, major_version_, minor_version_, + ttl_, ip_address_, port_reliable, ip_address_, port_unreliable); + + // Check it was added + auto service_list = its_manager->get_offered_services(); + ASSERT_TRUE(service_list.size() > 0); + + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_RESUMED); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_RESUMED); + + for (const auto &its_service : its_manager->get_offered_services()) { + for (const auto &its_instance : its_service.second) { + ASSERT_EQ(its_instance.second->get_ttl(), DEFAULT_TTL); + ASSERT_FALSE(its_instance.second->is_in_mainphase()); + } + } +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_SHUTDOWN) { + + // Call test method with test input. + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_SHUTDOWN); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_SHUTDOWN); +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_DIAGNOSIS) { + + // Adding a service using add_routing_info + its_manager->add_routing_info(service_, instance_, major_version_, minor_version_, + ttl_, ip_address_, port_reliable, ip_address_, port_unreliable); + + // Check it was added + auto service_list = its_manager->get_offered_services(); + ASSERT_TRUE(service_list.size() > 0); + + // Call test method with test input. + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_DIAGNOSIS); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_DIAGNOSIS); + + // Check ttl was set to 0 done in discovery_->stop_offer_service + for (const auto &its_service : its_manager->get_offered_services()) { + for (const auto &its_instance : its_service.second) { + ASSERT_EQ(its_instance.second->get_ttl(), 0); + } + } +} + +TEST_F(routing_manager_ut_setup, DISABLED_set_routing_state_RS_UNKNOWN) { + + // RS_RUNNING is the default value so set RS_UNKOWN + its_manager->set_routing_state(vsomeip_v3::routing_state_e::RS_UNKNOWN); + + // Assert routing state, is equal to tested state. + ASSERT_EQ(its_manager->get_routing_state(), vsomeip_v3::routing_state_e::RS_UNKNOWN); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/CMakeLists.txt new file mode 100644 index 00000000000..9c864e80d2f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_policy_manager_impl_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +# configure macro.hpp for correct path +set(UNIT_TEST_BIN_DIR ${CMAKE_SOURCE_DIR}/build/test/unit_tests) + +configure_file( + "${CMAKE_SOURCE_DIR}/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp.in" + "${CMAKE_SOURCE_DIR}/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp" +) + +file(MAKE_DIRECTORY ${UNIT_TEST_BIN_DIR}/security_policy_manager_impl_tests/0_0) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp.in b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp.in new file mode 100644 index 00000000000..60f5480550d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/policy_manager_impl_unit_test_macro.hpp.in @@ -0,0 +1,10 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef policy_manager_impl_unit_test +#define policy_manager_impl_unit_test + +#define UNIT_TEST_BUILD_DIR_PATH "@UNIT_TEST_BIN_DIR@" +#endif diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/ut_policy_manager_impl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/ut_policy_manager_impl.cpp new file mode 100644 index 00000000000..0647977f5d4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_manager_impl_tests/ut_policy_manager_impl.cpp @@ -0,0 +1,1372 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifdef _WIN32 +#include <Windows.h> +#endif + +#include <gtest/gtest.h> +#include <vsomeip/defines.hpp> + +#include <boost/property_tree/ptree.hpp> + +#include "../../../implementation/configuration/include/configuration_element.hpp" +#include "../../../implementation/security/include/policy.hpp" +#include "../../../implementation/security/include/policy_manager_impl.hpp" +#include "../../../implementation/utility/include/bithelper.hpp" +#include "../../../implementation/utility/include/utility.hpp" + +#include "policy_manager_impl_unit_test_macro.hpp" + +namespace { + // Lazy load. + bool lazy_load = true; + bool not_lazy_load = false; + + // Client uint16_t + const vsomeip_v3::client_t client_number = 0x1000; + const vsomeip_v3::service_t service_number = 0x1337; + const vsomeip_v3::service_t offer_service_number = 0x1001; + const vsomeip_v3::instance_t instance_number = 0x0101; + const vsomeip_v3::instance_t offer_instance_number = 0x7080; + const vsomeip_v3::method_t method_number = 0x0202; + + // Arbitrary array size, will depends on the policy itself. + const std::uint32_t array_size = 82; + + // Credentials. + const vsomeip_v3::byte_t uid_byte1 = 0x01; + const vsomeip_v3::byte_t uid_byte2 = 0x02; + const vsomeip_v3::byte_t uid_byte3 = 0x03; + const vsomeip_v3::byte_t uid_byte4 = 0x04; + const vsomeip_v3::byte_t gid_byte1 = 0x05; + const vsomeip_v3::byte_t gid_byte2 = 0x06; + const vsomeip_v3::byte_t gid_byte3 = 0x07; + const vsomeip_v3::byte_t gid_byte4 = 0x08; + + // Policy requests length, with respective service number(s). + const vsomeip_v3::byte_t request_length_byte1 = 0x00; + const vsomeip_v3::byte_t request_length_byte2 = 0x00; + const vsomeip_v3::byte_t request_length_byte3 = 0x00; + const vsomeip_v3::byte_t request_length_byte4 = 38; // Decimal to simplify. + const vsomeip_v3::byte_t request_service_byte1 = 0x13; + const vsomeip_v3::byte_t request_service_byte2 = 0x37; + + // Policy offers length, with respective service number(s). + const vsomeip_v3::byte_t offer_length_byte1 = 0x00; + const vsomeip_v3::byte_t offer_length_byte2 = 0x00; + const vsomeip_v3::byte_t offer_length_byte3 = 0x00; + const vsomeip_v3::byte_t offer_length_byte4 = 28; // Decimal to simplify. + const vsomeip_v3::byte_t offer_service_byte1 = 0x10; + const vsomeip_v3::byte_t offer_service_byte2 = 0x01; + + // Length deserialized by deserialize_ids. + const vsomeip_v3::byte_t id_array_length_byte1 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte2 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte3 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte4 = 32; // Decimal to simplify. + + // Length deserialized by requests' first call to deserialize_id_item_list. + const vsomeip_v3::byte_t request_instance_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte4 = 12; + + // Length deserialized by offers' call to deserialize_id_item_list. + const vsomeip_v3::byte_t offer_instance_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte4 = 22; // Decimal to simplify. + + // Length deserialized by deserialize_id_item for instances. (Represent either 2*uint16_t = 4 bytes, or uint16_t = 2 bytes) + const vsomeip_v3::byte_t instance_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte4 = 0x04; + + // Message type parsed in deserialize_id_item should be either 1 or 2. + const vsomeip_v3::byte_t instance_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte4 = 0x02; + + // Low and High of the instance interval, if type 1 only low is necessary. + const vsomeip_v3::byte_t instance_id_low_byte1 = 0x01; + const vsomeip_v3::byte_t instance_id_low_byte2 = 0x01; + const vsomeip_v3::byte_t instance_id_high_byte1 = 0x10; + const vsomeip_v3::byte_t instance_id_high_byte2 = 0x10; + + // Length deserialized by requests' second call to deserialize_id_item_list. + const vsomeip_v3::byte_t request_method_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte4 = 12; // Decimal to simplify. + + // Length deserialized by deserialize_id_item for Methods. + const vsomeip_v3::byte_t method_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte4 = 0x04; + + // Message type parsed in deserialize_id_item should be either 1 or 2. + const vsomeip_v3::byte_t method_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte4 = 0x02; + + // Low and High of the instance interval, for message type 2. + const vsomeip_v3::byte_t method_id_low_byte1 = 0x02; + const vsomeip_v3::byte_t method_id_low_byte2 = 0x02; + const vsomeip_v3::byte_t method_id_high_byte1 = 0x20; + const vsomeip_v3::byte_t method_id_high_byte2 = 0x20; + + // Length deserialized by deserialize_id_item for second instance. (represent either 2*uint16_t = 4, or uint16 = 2) + const vsomeip_v3::byte_t instance2_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte4 = 0x02; + + // Message type parsed in deserialize_id_item. + const vsomeip_v3::byte_t instance2_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte4 = 0x01; + + // Message type 1 only includes low bound. + const vsomeip_v3::byte_t instance2_id_low_byte1 = 0x70; + const vsomeip_v3::byte_t instance2_id_low_byte2 = 0x80; + + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_array_uid_{uid_byte1, uid_byte2, uid_byte3, uid_byte4}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_gid_{gid_byte1, gid_byte2, gid_byte3, gid_byte4}; + + // Create uint32_t from bytes. + const std::uint32_t uid = vsomeip_v3::bithelper::read_uint32_be(uint32_array_uid_.data()); + const std::uint32_t gid = vsomeip_v3::bithelper::read_uint32_be(uint32_array_gid_.data()); + +} + +TEST(security_policy_manager_test, load) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // is_audit returns !check_credentials_ which is by default false, so is_audit should return true. + ASSERT_TRUE(its_policy_manager->is_audit()); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Test Method. Load policy element, which should set check_credentials to true. + its_policy_manager->load(its_element, lazy_load); + + // Check that is_audit now returns false. Since check_credentials should now be true if the load worked. + ASSERT_FALSE(its_policy_manager->is_audit()); +} + +TEST(security_policy_manager_test, check_credentials) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Default test structure, case will fall through the logic checks to the end of the test method. + vsomeip_sec_client_t its_client_struct_default; + + its_client_struct_default.user = 0; + its_client_struct_default.group = 0; + its_client_struct_default.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct_default.host = 0; + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Test Method, policy not enabled, expect call to return true. + ASSERT_TRUE(its_policy_manager->check_credentials(client_number, &its_client_struct)); + + // Create policy to be able to test the method further. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Add policy to the manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should set check_credentials to true. Needed to differentiate returns test cases (sets the default test to false). + its_policy_manager->load(its_element, lazy_load); + + // Test Method, client null expect call to return true. + ASSERT_TRUE(its_policy_manager->check_credentials(client_number, nullptr)); + + // Set port to be different from 0 + its_client_struct.port = 1; + + // Test Method, port != 0, expect call to return true. + ASSERT_TRUE(its_policy_manager->check_credentials(client_number, &its_client_struct)); + + // reset port to 0 + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + + // Test Method, expect call to return true. + ASSERT_TRUE(its_policy_manager->check_credentials(client_number, &its_client_struct)); + + // Test Method, expect call to default through and return !check_credentials. Since we set it to true we expect false. + ASSERT_FALSE(its_policy_manager->check_credentials(0, &its_client_struct_default)); +} + +TEST(security_policy_manager_test, check_routing_credentials) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Default test structure, case will fall through the logic checks to the end of the test method. + vsomeip_sec_client_t its_client_struct_default; + + its_client_struct_default.user = 0; + its_client_struct_default.group = 0; + its_client_struct_default.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct_default.host = 0; + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Add policy to the manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Create a policy element setting check_credentials to true. And check_routing_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + boost::property_tree::ptree tree_check_routing_credentials; + boost::property_tree::ptree tree_check_routing_credentials_uid; + boost::property_tree::ptree tree_check_routing_credentials_gid; + + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + tree_check_routing_credentials_uid.put_value("0x01020304"); + tree_check_routing_credentials_gid.put_value("0x05060708"); + tree_check_routing_credentials.add_child("uid", tree_check_routing_credentials_uid); + tree_check_routing_credentials.add_child("gid", tree_check_routing_credentials_gid); + tree.add_child("routing-credentials", tree_check_routing_credentials); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Test Method, expect call to return true. This method, defaults even with nullptr, no null checks. + ASSERT_TRUE(its_policy_manager->check_routing_credentials(nullptr)); + + // Load policy element not lazy load, to call load_routing_credentials which should set check_routing_credentials_ to true. + its_policy_manager->load(its_element, not_lazy_load); + + // Test Method, expect call to default through and return !check_routing_credentials. Since we set it to true we expect false. + ASSERT_FALSE(its_policy_manager->check_routing_credentials(&its_client_struct_default)); + + // Test Method, expect call to return true. + ASSERT_TRUE(its_policy_manager->check_routing_credentials(&its_client_struct)); +} + +TEST(security_policy_manager_test, set_routing_credentials) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Default test structure, case will fall through the logic checks to the end of the test method. + vsomeip_sec_client_t its_client_struct_default; + + its_client_struct_default.user = 0; + its_client_struct_default.group = 0; + its_client_struct_default.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct_default.host = 0; + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + const std::string routing_name = "random"; + // Test method + its_policy_manager->set_routing_credentials(uid, gid, routing_name); + + // Test Method, expect call to default through and return !check_routing_credentials. Since it is false by default, we expect true. + ASSERT_TRUE(its_policy_manager->check_routing_credentials(&its_client_struct_default)); + + // Test Method, expect call to return true. + ASSERT_TRUE(its_policy_manager->check_routing_credentials(&its_client_struct)); +} + +TEST(security_policy_manager_test, is_client_allowed) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Default test structure, case will fall through the logic checks to the end of the test method. + vsomeip_sec_client_t its_client_struct_default; + + its_client_struct_default.user = 0; + its_client_struct_default.group = 0; + its_client_struct_default.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct_default.host = 0; + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Test Method. Policy not enabled + ASSERT_TRUE(its_policy_manager->is_client_allowed(&its_client_struct, service_number, instance_number, method_number, true)); + + // Enable policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Add policy to the manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should set check_credentials to true. Needed to differentiate returns test cases (sets the default test to false). + its_policy_manager->load(its_element, lazy_load); + + // Set port to a number different than 0 + its_client_struct.port = 1; + // Test Method. Expect to receive true since the port is not 0 + ASSERT_TRUE(its_policy_manager->is_client_allowed(&its_client_struct, service_number, instance_number, method_number, true)); + //reset port to 0. + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + + // Test Method. client is null. Expect !check_credentials. + ASSERT_FALSE(its_policy_manager->is_client_allowed(nullptr, service_number, instance_number, method_number, true)); + + // Test Method. Expect true, is matching is true, and client is added to cache. + ASSERT_TRUE(its_policy_manager->is_client_allowed(&its_client_struct, service_number, instance_number, method_number, true)); + + // Test Method. Expect true, case in cache. + ASSERT_TRUE(its_policy_manager->is_client_allowed(&its_client_struct, service_number, instance_number, method_number, true)); + + // Allow what false. + its_policy->allow_what_= false; + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Test Method expect true from return where allow what is false. + ASSERT_TRUE(its_policy_manager->is_client_allowed(&its_client_struct, service_number, instance_number, 1, false)); + + // Test method, expect !check_credentials which we set to true, so expect false. + ASSERT_FALSE(its_policy_manager->is_client_allowed(&its_client_struct_default, service_number, instance_number, method_number, true)); +} + + +TEST(security_policy_manager_test, is_offer_allowed) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Default test structure, case will fall through the logic checks to the end of the test method. + vsomeip_sec_client_t its_client_struct_default; + + its_client_struct_default.user = 0; + its_client_struct_default.group = 0; + its_client_struct_default.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct_default.host = 0; + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Test Method. Policy not enabled + ASSERT_TRUE(its_policy_manager->is_offer_allowed(&its_client_struct, offer_service_number, offer_instance_number)); + + // Enable policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Add policy to the manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should set check_credentials to true. Needed to differentiate returns test cases (sets the default test to false). + its_policy_manager->load(its_element, lazy_load); + + // Set port to a number different than 0 + its_client_struct.port = 1; + // Test Method. Expect to receive true since the port is not 0 + ASSERT_TRUE(its_policy_manager->is_offer_allowed(&its_client_struct, offer_service_number, offer_instance_number)); + //reset port to 0. + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + + // Test Method. client is null. Expect !check_credentials. + ASSERT_FALSE(its_policy_manager->is_offer_allowed(nullptr, offer_service_number, offer_instance_number)); + + // Test Method. Expect true, is matching is true, and client is added to cache. + ASSERT_TRUE(its_policy_manager->is_offer_allowed(&its_client_struct, offer_service_number, offer_instance_number)); + + // Test method, expect !check_credentials which we set to true, so expect false. + ASSERT_FALSE(its_policy_manager->is_offer_allowed(&its_client_struct_default, offer_service_number, offer_instance_number)); +} + +TEST(security_policy_manager_test, store_sec_client_to_client_mapping_and_get_sec_client_to_clients_mapping) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + std::set<vsomeip_v3::client_t> client_set; + + // Test method, expect false since sec client is null. + ASSERT_FALSE(its_policy_manager->get_sec_client_to_clients_mapping(nullptr, client_set)); + + // Set client structure port to different than 0. + its_client_struct.port = 1; + // Test method expect false since port != 0. + ASSERT_FALSE(its_policy_manager->get_sec_client_to_clients_mapping(&its_client_struct, client_set)); + // reset port to 0 + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + + // Test method, correct call but expect false since we have yet to add a client to the mapping. + ASSERT_FALSE(its_policy_manager->get_sec_client_to_clients_mapping(&its_client_struct, client_set)); + + // Test method, add a client to the client mapping. + its_policy_manager->store_sec_client_to_client_mapping(&its_client_struct, client_number); + + // Test method, expect true since the client was added to the mapping. + ASSERT_TRUE(its_policy_manager->get_sec_client_to_clients_mapping(&its_client_struct, client_set)); +} + +TEST(security_policy_manager_test, store_client_to_sec_client_mapping) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + + // Test method, expect false since sec client is null. + ASSERT_FALSE(its_policy_manager->store_client_to_sec_client_mapping(client_number, nullptr)); + + // Set client structure port to different than 0. + its_client_struct.port = 1; + // Test method expect false since port != 0. + ASSERT_FALSE(its_policy_manager->store_client_to_sec_client_mapping(client_number, &its_client_struct)); + // reset port to 0 + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + + // Test method, expect true as we are adding a client. + ASSERT_TRUE(its_policy_manager->store_client_to_sec_client_mapping(client_number, &its_client_struct)); +} + +TEST(security_policy_manager_test, get_client_to_sec_client_mapping) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Test method, expect false since we have yet to store a client. + ASSERT_FALSE(its_policy_manager->get_client_to_sec_client_mapping(client_number, its_client_struct)); + + // store a client to client mapping. + ASSERT_TRUE(its_policy_manager->store_client_to_sec_client_mapping(client_number, &its_client_struct)); + + // Test method, expect true since we stored the client previously. + ASSERT_TRUE(its_policy_manager->get_client_to_sec_client_mapping(client_number, its_client_struct)); +} + +TEST(security_policy_manager_test, remove_client_to_sec_client_mapping) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Test method, expect false since we have yet to store a client. + ASSERT_FALSE(its_policy_manager->remove_client_to_sec_client_mapping(client_number)); + + // store a client to client mapping. + ASSERT_TRUE(its_policy_manager->store_client_to_sec_client_mapping(client_number, &its_client_struct)); + its_policy_manager->store_sec_client_to_client_mapping(&its_client_struct, client_number); + + // Test method, expect true since we stored the client previously. + ASSERT_TRUE(its_policy_manager->remove_client_to_sec_client_mapping(client_number)); +} + +TEST(security_policy_manager_test, parse_policy) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + std::uint32_t deserialized_uid, deserialized_gid; + + // Test method. + #ifndef __QNX__ + ASSERT_TRUE(its_policy_manager->parse_policy(data_ptr_, data_size_, deserialized_uid, deserialized_gid, its_policy)); + #endif + + ASSERT_EQ(uid, deserialized_uid); + ASSERT_EQ(gid, deserialized_gid); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_too_short[4]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4 + }; + + const vsomeip_v3::byte_t *data_ptr2_ = byte_array_too_short; + std::uint32_t data_size2_ = 4; + + // Test Method, expect false. + #ifndef __QNX__ + ASSERT_FALSE(its_policy_manager->parse_policy(data_ptr2_, data_size2_, deserialized_uid, deserialized_gid, its_policy)); + #endif +} + +TEST(security_policy_manager_test, parse_uid_gid) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + std::uint32_t deserialized_uid, deserialized_gid; + + // Test method. + #ifndef __QNX__ + ASSERT_TRUE(its_policy_manager->parse_uid_gid(data_ptr_, data_size_, deserialized_uid, deserialized_gid)); + #endif + + ASSERT_EQ(uid, deserialized_uid); + ASSERT_EQ(gid, deserialized_gid); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_too_short[4]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4 + }; + + const vsomeip_v3::byte_t *data_ptr2_ = byte_array_too_short; + std::uint32_t data_size2_ = 4; + + // Test Method, expect false. + #ifndef __QNX__ + ASSERT_FALSE(its_policy_manager->parse_uid_gid(data_ptr2_, data_size2_, deserialized_uid, deserialized_gid)); + #endif +} + +TEST(security_policy_manager_test, remove_security_policy) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test method. Expect false since no policy was added. + ASSERT_FALSE(its_policy_manager->remove_security_policy(uid, gid)); + + // Add a policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Add policy to the manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Test method. Expect true since we added a policy. + ASSERT_TRUE(its_policy_manager->remove_security_policy(uid, gid)); +} + +TEST(security_policy_manager_test, add_security_credentials) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Add a policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Test method. Add security credentials. + its_policy_manager->add_security_credentials(uid, gid, its_policy, client_number); + + // Expect true since we added the security credentials policy above. + ASSERT_TRUE(its_policy_manager->remove_security_policy(uid, gid)); +} + +TEST(security_policy_manager_test, get_requester_policies) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Add a policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + std::shared_ptr<vsomeip_v3::policy> its_policy2(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + request_service_byte1, request_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + std::set<std::shared_ptr<vsomeip_v3::policy>> its_policy_set= {}; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Test set is empty. + ASSERT_TRUE(its_policy_set.empty()); + + // Test method. + its_policy_manager->get_requester_policies(its_policy, its_policy_set); + + // Since the policy was not added to the manager, expect set to be empty still. + ASSERT_TRUE(its_policy_set.empty()); + + // Add policy to manager. + its_policy_manager->update_security_policy(uid, gid, its_policy); + + // Test method. + its_policy_manager->get_requester_policies(its_policy, its_policy_set); + + // Expect true because of the continue in the for loops if its_policy is equal to the policy in the manager. + ASSERT_TRUE(its_policy_set.empty()); + + // reseting data. + data_ptr_ = byte_array_; + data_size_ = array_size; + + // Set up new policy2. + ASSERT_TRUE(its_policy2->deserialize(data_ptr_, data_size_)); + its_policy_manager->update_security_policy(uid, gid, its_policy2); + + // Test method. + its_policy_manager->get_requester_policies(its_policy2, its_policy_set); + + // Expect the set to now be populated. + ASSERT_FALSE(its_policy_set.empty()); +} + +TEST(security_policy_manager_test, get_clients) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test Structure. + vsomeip_sec_client_t its_client_struct; + + its_client_struct.user = uid; + its_client_struct.group = gid; + its_client_struct.port = VSOMEIP_SEC_PORT_UNUSED; + its_client_struct.host = 0; + + // Add a policy. + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + std::unordered_set<vsomeip_v3::client_t> its_client_set= {}; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Assert set is empty. + ASSERT_TRUE(its_client_set.empty()); + + // Test method. + its_policy_manager->get_clients(uid, gid, its_client_set); + + // Since no client was added, expect the set to remain empty. + ASSERT_TRUE(its_client_set.empty()); + + // Add client to manager. + ASSERT_TRUE(its_policy_manager->store_client_to_sec_client_mapping(client_number, &its_client_struct)); + + // Test method. + its_policy_manager->get_clients(uid, gid, its_client_set); + + // Expect false since we added a client to the manager. + ASSERT_FALSE(its_client_set.empty()); + ASSERT_EQ(its_client_set.size(), 1); + + // Add client to manager. + ASSERT_TRUE(its_policy_manager->store_client_to_sec_client_mapping(client_number + 1, &its_client_struct)); + + // test method. + its_policy_manager->get_clients(uid, gid, its_client_set); + + // Expect set to have 2 entries. + ASSERT_EQ(its_client_set.size(), 2); +} + +TEST(security_policy_manager_test, get_policy_extension_path) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + const std::string its_client_host = "random"; + + // Test Method. + ASSERT_EQ(its_policy_manager->get_policy_extension_path(its_client_host), ""); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + boost::property_tree::ptree tree_container_policy_extensions; + boost::property_tree::ptree tree_container_policy_extension; + boost::property_tree::ptree tree_container_policy_extensions_container; + boost::property_tree::ptree tree_container_policy_extensions_path; + tree_container_policy_extensions_container.put_value("random"); + tree_container_policy_extensions_path.put_value("/random_path/"); + tree_container_policy_extension.add_child("container", tree_container_policy_extensions_container); + tree_container_policy_extension.add_child("path", tree_container_policy_extensions_path); + tree_container_policy_extensions.add_child("extension", tree_container_policy_extension); + tree.add_child("container_policy_extensions", tree_container_policy_extensions); + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should should add the container and its path to policy_extension_paths_. + its_policy_manager->load(its_element, not_lazy_load); + + // Test method + ASSERT_EQ(its_policy_manager->get_policy_extension_path(its_client_host), "/etc/random_path/"); +} + +TEST(security_policy_manager_test, is_policy_removal_allowed) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Test method. Expect true because it will return the default option !check_whitelist_ which is false. + ASSERT_TRUE(its_policy_manager->is_policy_removal_allowed(uid)); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_check_whitelists; + boost::property_tree::ptree tree_security_update_whitelist; + boost::property_tree::ptree tree_whitelists_any_interval; + + // Change check_whitelist_ to true, so we get false if we get the previous return. + tree_check_whitelists.put_value("true"); + tree_security_update_whitelist.add_child("check-whitelist", tree_check_whitelists); + + // Set any interval so we should get true if the uid is contained within the min and max. + tree_whitelists_any_interval.put_value("any"); + tree_security_update_whitelist.add_child("uids", tree_whitelists_any_interval); + tree.add_child("security-update-whitelist", tree_security_update_whitelist); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should should add the container and its path to policy_extension_paths_. + its_policy_manager->load(its_element, not_lazy_load); + + // Test method. Expect true. Since we set up an interval, if uid is between 0 and max uint32_t we should get true. + ASSERT_TRUE(its_policy_manager->is_policy_removal_allowed(uid)); +} + +TEST(security_policy_manager_test, is_policy_update_allowed) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Create a policy + // Policy shared pointer to be used for test set up. + std::shared_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy + vsomeip_v3::byte_t byte_array_[array_size]{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t *data_ptr_ = byte_array_; + std::uint32_t data_size_ = array_size; + + // Filling in the policy. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Test method. Expect true because it will return the default option !check_whitelist_ which is false. + ASSERT_TRUE(its_policy_manager->is_policy_update_allowed(uid, its_policy)); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_check_whitelists; + boost::property_tree::ptree tree_security_update_whitelist; + boost::property_tree::ptree tree_whitelists_any_interval; + + // Change check_whitelist_ to true, so we get false if we get the previous return. + tree_check_whitelists.put_value("true"); + tree_security_update_whitelist.add_child("check-whitelist", tree_check_whitelists); + + // Set any interval for uid and services so we should get true if the uid is contained within the min and max. + tree_whitelists_any_interval.put_value("any"); + tree_security_update_whitelist.add_child("uids", tree_whitelists_any_interval); + tree_whitelists_any_interval.put_value("any"); + tree_security_update_whitelist.add_child("services", tree_whitelists_any_interval); + tree.add_child("security-update-whitelist", tree_security_update_whitelist); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Load policy element, which should should add the container and its path to policy_extension_paths_. + its_policy_manager->load(its_element, not_lazy_load); + + // Test method. Expect true because uid and service matched. + ASSERT_TRUE(its_policy_manager->is_policy_update_allowed(uid, its_policy)); +} + +TEST(security_policy_manager_test, get_security_config_folder) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Create a string stream to build the full path to the security config folder. + std::stringstream final_path; + + // Create a string to the path to the current unit test folder. + const std::string folder_path = UNIT_TEST_BUILD_DIR_PATH "/security_policy_manager_impl_tests"; + + const std::string fake_path = "fake_path"; + + // Test method, since the folder does not exist, expect a default return. + ASSERT_EQ(its_policy_manager->get_security_config_folder(fake_path), ""); + + // Complete the path, adding the uid and gid. +#ifdef _WIN32 + final_path << folder_path << "/0_0"; +#else + final_path << folder_path << "/" << getuid() << "_" << getgid(); +#endif + + // Convert stringstream to char* + const std::string tmp = final_path.str(); + const char* final_path_string = tmp.c_str(); + + boost::system::error_code ec; + // Create the directory. + boost::filesystem::create_directory(final_path_string, ec); + + // Test method. Since the folder now exists we expect to get the path returned. + ASSERT_EQ(its_policy_manager->get_security_config_folder(folder_path), final_path_string); + + // Clean up, remove directory. + boost::filesystem::remove_all(final_path_string, ec); +} + +TEST(security_policy_manager_test, is_policy_extension_loaded) { + // Test pointer. + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_policy_manager(new vsomeip_v3::policy_manager_impl()); + + // Client name. + const std::string client_name("random"); + + // Test method. No path has yet to be added. + ASSERT_EQ(its_policy_manager->is_policy_extension_loaded(client_name), + vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT); + + // Create a string stream to build the relative path to the security config folder. + std::stringstream final_path; + + // Create a secondary path which will be full path. + std::stringstream final_path2; + + // Create a string of the build path to the current test. + const std::string folder_path = "build/test/unit_tests/security_policy_manager_impl_tests"; + + // Complete the path, adding the uid and gid. +#ifdef _WIN32 + final_path << folder_path << "/0_0"; +#else + final_path << folder_path << "/" << getuid() << "_" << getgid(); +#endif + + // Add a way to move out of the /etc folder we will be forced in. + final_path2 << "../.." << UNIT_TEST_BUILD_DIR_PATH << "/security_policy_manager_impl_tests"; + + // Convert stringstream to char* + const std::string tmp = final_path.str(); + const char* final_path_string = tmp.c_str(); + const std::string tmp2 = final_path2.str(); + const char* final_path_string2 = tmp2.c_str(); + + boost::system::error_code ec; + // Create the directory. + boost::filesystem::create_directory(final_path_string, ec); + + // Create a policy element setting check_credentials to true. + const std::string element_name = "random"; + boost::property_tree::ptree tree; + boost::property_tree::ptree tree_security; + boost::property_tree::ptree tree_check_credentials; + boost::property_tree::ptree tree_container_policy_extensions; + boost::property_tree::ptree tree_container_policy_extension; + boost::property_tree::ptree tree_container_policy_extensions_container; + boost::property_tree::ptree tree_container_policy_extensions_path; + tree_container_policy_extensions_container.put_value("random"); + tree_container_policy_extensions_path.put_value(final_path_string2); + tree_container_policy_extension.add_child("container", tree_container_policy_extensions_container); + tree_container_policy_extension.add_child("path", tree_container_policy_extensions_path); + tree_container_policy_extensions.add_child("extension", tree_container_policy_extension); + tree.add_child("container_policy_extensions", tree_container_policy_extensions); + tree_check_credentials.put_value("true"); + tree_security.add_child("check_credentials", tree_check_credentials); + tree.add_child("security", tree_security); + + const boost::property_tree::ptree tree_ptr = tree; + vsomeip_v3::configuration_element its_element(element_name, tree_ptr); + + // Need to load a policy extension. + its_policy_manager->load(its_element, not_lazy_load); + + // Test method. Expect an inexistent return because the set_is_plocity_extension_loaded method hasn't be called. + ASSERT_EQ(its_policy_manager->is_policy_extension_loaded(client_name), + vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT); + + // Associated test method. True for loaded. + its_policy_manager->set_is_policy_extension_loaded(client_name, true); + + // Test method. Expect an outcome different from the last since we called the method. + ASSERT_NE(its_policy_manager->is_policy_extension_loaded(client_name), + vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT); + + // Test method. Since we used true for loaded in the set method we expect found and loaded return. + ASSERT_EQ(its_policy_manager->is_policy_extension_loaded(client_name), + vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_LOADED); + + // Associated test method. False for loaded. + its_policy_manager->set_is_policy_extension_loaded(client_name, false); + + // Test method. We now expect found but not loaded return. + ASSERT_EQ(its_policy_manager->is_policy_extension_loaded(client_name), + vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_FOUND_AND_NOT_LOADED); + + // Clean up, remove directory. + boost::filesystem::remove_all(final_path_string, ec); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/CMakeLists.txt new file mode 100644 index 00000000000..a989a39ebf1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_policy_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/ut_policy.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/ut_policy.cpp new file mode 100644 index 00000000000..eb63bd0babf --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_policy_tests/ut_policy.cpp @@ -0,0 +1,404 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> +#include <vsomeip/defines.hpp> + +#include "../../../implementation/utility/include/bithelper.hpp" +#include "../../../implementation/security/include/policy.hpp" + +namespace { + // Arbitrary array size, will depends on the policy itself. + const std::uint32_t array_size = 82; + + // Credentials. + const vsomeip_v3::byte_t uid_byte1 = 0x01; + const vsomeip_v3::byte_t uid_byte2 = 0x02; + const vsomeip_v3::byte_t uid_byte3 = 0x03; + const vsomeip_v3::byte_t uid_byte4 = 0x04; + const vsomeip_v3::byte_t gid_byte1 = 0x05; + const vsomeip_v3::byte_t gid_byte2 = 0x06; + const vsomeip_v3::byte_t gid_byte3 = 0x07; + const vsomeip_v3::byte_t gid_byte4 = 0x08; + + // Policy requests length, with respective service number(s). + const vsomeip_v3::byte_t request_length_byte1 = 0x00; + const vsomeip_v3::byte_t request_length_byte2 = 0x00; + const vsomeip_v3::byte_t request_length_byte3 = 0x00; + const vsomeip_v3::byte_t request_length_byte4 = 38; // Decimal to simplify. + const vsomeip_v3::byte_t request_service_byte1 = 0x13; + const vsomeip_v3::byte_t request_service_byte2 = 0x37; + + // Policy offers length, with respective service number(s). + const vsomeip_v3::byte_t offer_length_byte1 = 0x00; + const vsomeip_v3::byte_t offer_length_byte2 = 0x00; + const vsomeip_v3::byte_t offer_length_byte3 = 0x00; + const vsomeip_v3::byte_t offer_length_byte4 = 28; // Decimal to simplify. + const vsomeip_v3::byte_t offer_service_byte1 = 0x10; + const vsomeip_v3::byte_t offer_service_byte2 = 0x01; + + // Length deserialized by deserialize_ids. + const vsomeip_v3::byte_t id_array_length_byte1 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte2 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte3 = 0x00; + const vsomeip_v3::byte_t id_array_length_byte4 = 32; // Decimal to simplify. + + // Length deserialized by requests' first call to deserialize_id_item_list. + const vsomeip_v3::byte_t request_instance_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t request_instance_idlist_byte4 = 12; + + // Length deserialized by offers' call to deserialize_id_item_list. + const vsomeip_v3::byte_t offer_instance_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t offer_instance_idlist_byte4 = 22; // Decimal to simplify. + + // Length deserialized by deserialize_id_item for instances. (Represent either 2*uint16_t = 4 bytes, or uint16_t = 2 bytes) + const vsomeip_v3::byte_t instance_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t instance_id_length_byte4 = 0x04; + + // Message type parsed in deserialize_id_item should be either 1 or 2. + const vsomeip_v3::byte_t instance_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t instance_id_type_byte4 = 0x02; + + // Low and High of the instance interval, if type 1 only low is necessary. + const vsomeip_v3::byte_t instance_id_low_byte1 = 0x01; + const vsomeip_v3::byte_t instance_id_low_byte2 = 0x01; + const vsomeip_v3::byte_t instance_id_high_byte1 = 0x10; + const vsomeip_v3::byte_t instance_id_high_byte2 = 0x10; + + // Length deserialized by requests' second call to deserialize_id_item_list. + const vsomeip_v3::byte_t request_method_idlist_byte1 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte2 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte3 = 0x00; + const vsomeip_v3::byte_t request_method_idlist_byte4 = 12; // Decimal to simplify. + + // Length deserialized by deserialize_id_item for Methods. + const vsomeip_v3::byte_t method_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t method_id_length_byte4 = 0x04; + + // Message type parsed in deserialize_id_item should be either 1 or 2. + const vsomeip_v3::byte_t method_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t method_id_type_byte4 = 0x02; + + // Low and High of the instance interval, for message type 2. + const vsomeip_v3::byte_t method_id_low_byte1 = 0x02; + const vsomeip_v3::byte_t method_id_low_byte2 = 0x02; + const vsomeip_v3::byte_t method_id_high_byte1 = 0x20; + const vsomeip_v3::byte_t method_id_high_byte2 = 0x20; + + // Length deserialized by deserialize_id_item for second instance. (represent either 2*uint16_t = 4, or uint16 = 2) + const vsomeip_v3::byte_t instance2_id_length_byte1 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte2 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte3 = 0x00; + const vsomeip_v3::byte_t instance2_id_length_byte4 = 0x02; + + // Message type parsed in deserialize_id_item. + const vsomeip_v3::byte_t instance2_id_type_byte1 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte2 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte3 = 0x00; + const vsomeip_v3::byte_t instance2_id_type_byte4 = 0x01; + + // Message type 1 only includes low bound. + const vsomeip_v3::byte_t instance2_id_low_byte1 = 0x70; + const vsomeip_v3::byte_t instance2_id_low_byte2 = 0x80; + + // Create arrays to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_array_uid_{uid_byte1, uid_byte2, uid_byte3, uid_byte4}; + std::array<vsomeip_v3::byte_t, 4> uint32_array_gid_{gid_byte1, gid_byte2, gid_byte3, gid_byte4}; + + // Create uint32_t from bytes. + const std::uint32_t uid = vsomeip_v3::bithelper::read_uint32_be(uint32_array_uid_.data()); + const std::uint32_t gid = vsomeip_v3::bithelper::read_uint32_be(uint32_array_gid_.data()); +} + +TEST(security_policy_test, deserialize) { + std::unique_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy with type 2 instance and methods for requests_ + // and two instances for offers one type 2 instance and one type 1 for offers_ + // type 2 receives a uint16_t for low_ and another for high_ + // for type 1 low_ = high_ and only 1 uint16_t is passed. + + std::array<vsomeip_v3::byte_t, array_size>byte_array_{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t* data_ptr_ = byte_array_.data(); + std::uint32_t data_size_ = array_size; + + // Test method. + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Check credentials. + + // Check if uid and gid were deserialized correctly by private method deserialize_u32 + // Check if uid is in the credentials_ + auto deserialized_gid_set = its_policy->credentials_.lower_bound( + boost::icl::interval<vsomeip_v3::uid_t>::closed(uid, uid)); + // Check if the associated gid is located. + ASSERT_EQ(deserialized_gid_set->second.begin()->lower(), gid); + + // Check requests + // Create uint16_t from bytes. + std::array<vsomeip_v3::byte_t, 2> uint16_array_request_service_{request_service_byte1, request_service_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_request_instance_low_{instance_id_low_byte1, instance_id_low_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_request_instance_high_{instance_id_high_byte1, instance_id_high_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_request_method_id_low_{method_id_low_byte1, method_id_low_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_request_method_id_high_{method_id_high_byte1, method_id_high_byte2}; + + std::uint16_t request_service = vsomeip_v3::bithelper::read_uint16_be(uint16_array_request_service_.data()); + std::uint16_t request_instance_low = vsomeip_v3::bithelper::read_uint16_be(uint16_array_request_instance_low_.data()); + std::uint16_t request_instance_high = vsomeip_v3::bithelper::read_uint16_be(uint16_array_request_instance_high_.data()); + std::uint16_t request_method_low = vsomeip_v3::bithelper::read_uint16_be(uint16_array_request_method_id_low_.data()); + std::uint16_t request_method_high = vsomeip_v3::bithelper::read_uint16_be(uint16_array_request_method_id_high_.data()); + + // Check if method high and low were deserialized correctly by private method deserialize_u16 + auto deserialized_service_set = its_policy->requests_.lower_bound( + boost::icl::interval<vsomeip_v3::service_t>::closed(request_service, request_service)); + + // Check if the associated instance low and high are located. + ASSERT_EQ(deserialized_service_set->second.begin()->first.lower(), request_instance_low); + ASSERT_EQ(deserialized_service_set->second.begin()->first.upper(), request_instance_high); + + auto deserialized_method_set = deserialized_service_set->second.lower_bound( + boost::icl::interval<vsomeip_v3::instance_t>::closed(request_instance_low, request_instance_high)); + + // Check if the associated request method low and high are located. + ASSERT_EQ(deserialized_method_set->second.begin()->lower(), request_method_low); + ASSERT_EQ(deserialized_method_set->second.begin()->upper(), request_method_high); + + // Check offers + // Create uint16_t from bytes. + std::array<vsomeip_v3::byte_t, 2> uint16_array_offer_service_{offer_service_byte1, offer_service_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_offer_instance_low_{instance_id_low_byte1, instance_id_low_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_offer_instance_high_{instance_id_high_byte1, instance_id_high_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_offer_instance2_low_{instance2_id_low_byte1, instance2_id_low_byte2}; + std::array<vsomeip_v3::byte_t, 2> uint16_array_offer_instance2_high_{instance2_id_low_byte1, instance2_id_low_byte2}; + + std::uint16_t offer_service = vsomeip_v3::bithelper::read_uint16_be(uint16_array_offer_service_.data()); + std::uint16_t offer_instance_low = vsomeip_v3::bithelper::read_uint16_be(uint16_array_offer_instance_low_.data()); + std::uint16_t offer_instance_high = vsomeip_v3::bithelper::read_uint16_be(uint16_array_offer_instance_high_.data()); + std::uint16_t offer_instance2_low = vsomeip_v3::bithelper::read_uint16_be(uint16_array_offer_instance2_low_.data()); + std::uint16_t offer_instance2_high = vsomeip_v3::bithelper::read_uint16_be(uint16_array_offer_instance2_high_.data()); + + // Check if method high and low were deserialized correctly by private method deserialize_u16 + auto deserialized_offer_service_set = its_policy->offers_.lower_bound( + boost::icl::interval<vsomeip_v3::instance_t>::closed(offer_service, offer_service)); + + // Check if the associated instance low and high are located. + ASSERT_EQ(deserialized_offer_service_set->second.begin()->lower(), offer_instance_low); + ASSERT_EQ(deserialized_offer_service_set->second.begin()->upper(), offer_instance_high); + + // Get the second interval added by the type 1 instance2, create an iterator and advance it. + // Note if the second interval falls within the first one or vise versa, since we are using an interval set, it will only have 1 item. + boost::icl::interval_set<vsomeip_v3::instance_t>::iterator it = deserialized_offer_service_set->second.begin(); + ASSERT_NE(++it, deserialized_offer_service_set->second.end()); + + // Check low and high are equal. + std::uint16_t offer_instance2_deserialized_lower = it->lower(); + std::uint16_t offer_instance2_deserialized_upper = it->upper(); + ASSERT_EQ(offer_instance2_deserialized_lower, offer_instance2_deserialized_upper); + ASSERT_EQ(offer_instance2_deserialized_lower, offer_instance2_low); + ASSERT_EQ(offer_instance2_deserialized_lower, offer_instance2_high); +} + +TEST(security_policy_test, serialize) { + std::unique_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy with type 2 instance and methods for requests_ + // Create a 54 length array. + const std::uint32_t resized_array_size = 54; + std::array<vsomeip_v3::byte_t, resized_array_size> byte_array_{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, 0 + // NOT SURE WHY THE SERIALIZATION IGNORES THE OFFERS. + // offer_service_byte1, offer_service_byte2, + // offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + // instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + // instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + // instance_id_low_byte1, instance_id_low_byte2, + // instance_id_high_byte1, instance_id_high_byte2, + // instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + // instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + // instance2_id_low_byte1, instance2_id_low_byte2 + }; + + // Fill policy with data. + const vsomeip_v3::byte_t* data_ptr_ = byte_array_.data(); + std::uint32_t data_size_ = array_size; + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Create a vector to receive the results of the serialization. + std::vector<vsomeip_v3::byte_t> byte_vector; + + // Test Method. + ASSERT_TRUE(its_policy->serialize(byte_vector)); + + // Check the vector length is equal to the original array size. + // the offer part of the policy does not get serialized. + ASSERT_EQ(byte_vector.size(), resized_array_size); + + // Check bytes. + for(std::uint32_t i = 0; i < byte_vector.size(); i++) + { + ASSERT_EQ(byte_vector.at(i), byte_array_[i]); + } + +} + +TEST(security_policy_test, get_uid_gid) { + std::unique_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy with type 2 instance and methods for requests_ + // and two instances for offers one type 2 instance and one type 1 for offers_ + // type 2 receives a uint16_t for low_ and another for high_ + // for type 1 low_ = high_ and only 1 uint16_t is passed. + std::array<vsomeip_v3::byte_t, array_size> byte_array_{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t* data_ptr_ = byte_array_.data(); + std::uint32_t data_size_ = array_size; + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Create uint32_t to receive the value from the test method. + std::uint32_t deserialized_uid; + std::uint32_t deserialized_gid; + + // Test method, and compare them to the created uid and gid. + #ifndef __QNX__ + ASSERT_TRUE(its_policy->get_uid_gid(deserialized_uid, deserialized_gid)); + #endif + ASSERT_EQ(deserialized_uid, uid); + ASSERT_EQ(deserialized_gid, gid); +} + +TEST(security_policy_test, deserialize_uid_gid) { + std::unique_ptr<vsomeip_v3::policy> its_policy(new vsomeip_v3::policy()); + + // Create an array of policy with type 2 instance and methods for requests_ + // and two instances for offers one type 2 instance and one type 1 for offers_ + // type 2 receives a uint16_t for low_ and another for high_ + // for type 1 low_ = high_ and only 1 uint16_t is passed. + std::array<vsomeip_v3::byte_t, array_size> byte_array_{ + uid_byte1, uid_byte2, uid_byte3, uid_byte4, + gid_byte1, gid_byte2, gid_byte3, gid_byte4, + request_length_byte1, request_length_byte2, request_length_byte3, request_length_byte4, + request_service_byte1, request_service_byte2, + id_array_length_byte1, id_array_length_byte2, id_array_length_byte3, id_array_length_byte4, + request_instance_idlist_byte1, request_instance_idlist_byte2, request_instance_idlist_byte3, request_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + request_method_idlist_byte1, request_method_idlist_byte2, request_method_idlist_byte3, request_method_idlist_byte4, + method_id_length_byte1, method_id_length_byte2, method_id_length_byte3, method_id_length_byte4, + method_id_type_byte1, method_id_type_byte2, method_id_type_byte3, method_id_type_byte4, + method_id_low_byte1, method_id_low_byte2, + method_id_high_byte1, method_id_high_byte2, + offer_length_byte1, offer_length_byte2, offer_length_byte3, offer_length_byte4, + offer_service_byte1, offer_service_byte2, + offer_instance_idlist_byte1, offer_instance_idlist_byte2, offer_instance_idlist_byte3, offer_instance_idlist_byte4, + instance_id_length_byte1, instance_id_length_byte2, instance_id_length_byte3, instance_id_length_byte4, + instance_id_type_byte1, instance_id_type_byte2, instance_id_type_byte3, instance_id_type_byte4, + instance_id_low_byte1, instance_id_low_byte2, + instance_id_high_byte1, instance_id_high_byte2, + instance2_id_length_byte1, instance2_id_length_byte2, instance2_id_length_byte3, instance2_id_length_byte4, + instance2_id_type_byte1, instance2_id_type_byte2, instance2_id_type_byte3, instance2_id_type_byte4, + instance2_id_low_byte1, instance2_id_low_byte2 + }; + + const vsomeip_v3::byte_t* data_ptr_ = byte_array_.data(); + std::uint32_t data_size_ = array_size; + ASSERT_TRUE(its_policy->deserialize(data_ptr_, data_size_)); + + // Create uint32_t to receive the value from the test method. + std::uint32_t deserialized_uid; + std::uint32_t deserialized_gid; + + // Resetting the pointers. + data_ptr_ = byte_array_.data(); + data_size_ = array_size; + + // Test method. + #ifndef __QNX__ + ASSERT_TRUE(its_policy->deserialize_uid_gid(data_ptr_, data_size_, deserialized_uid, deserialized_gid)); + #endif + ASSERT_EQ(deserialized_uid, uid); + ASSERT_EQ(deserialized_gid, gid); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/CMakeLists.txt new file mode 100644 index 00000000000..cc03debf7cc --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_security_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + Threads::Threads + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_credentials.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_credentials.cpp new file mode 100644 index 00000000000..2fe4e9dee9a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_credentials.cpp @@ -0,0 +1,123 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <common/utility.hpp> + +namespace { + vsomeip_v3::client_t client = 1; + vsomeip_v3::uid_t invalid_uid = 1; + vsomeip_v3::uid_t valid_uid = 4004201; + vsomeip_v3::gid_t invalid_gid = 1; + vsomeip_v3::gid_t valid_gid = 4004200; + vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(check_credentials_test, check_no_policies_loaded) { + + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + //no policies loaded -> check credentials will return false independent of the uid or gid + ASSERT_TRUE(its_manager->is_audit()); + ASSERT_FALSE(its_manager->is_enabled()); + + // create security clients + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_invalid)); +} + +TEST(check_credentials_test, check_policies_loaded) { + + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager( + new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + for (const auto& e : policy_elements) + its_manager->load(e, false); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + //the check_credentials_ and the policy_enabled_ variables should be set to true + ASSERT_FALSE(its_manager->is_audit()); + ASSERT_TRUE(its_manager->is_enabled()); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + //invalid uid and gid -> the check must return false + EXPECT_FALSE(its_manager->check_credentials(client, &its_sec_client_invalid)); + + //invalid uid and valid gid -> the check must return false + EXPECT_FALSE(its_manager->check_credentials(client, &its_sec_client_invalid)); + + //valid uid and invalid gid -> the check must return false + EXPECT_FALSE(its_manager->check_credentials(client, &its_sec_client_invalid)); + + //valid uid and gid -> the check must return true + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_valid)); +} + +// check_credentials with policies loaded but in audit mode +// vsomeip's security implementation can be put in a so called 'Audit Mode' where +// all security violations will be logged but allowed. +// To activate the 'Audit Mode' the 'security' object has to be included in the +// json file but the 'check_credentials' switch has to be set to false. +TEST(check_credentials_test, check_policies_loaded_in_audit_mode) { + + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager( + new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + //the check_credentials_ variable is force to be false + utility::force_check_credentials(policy_elements, "false"); + + for (const auto& e : policy_elements) + its_manager->load(e, false); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + //expect check_credentials_ false and the policy_enabled_ true + ASSERT_TRUE(its_manager->is_audit()); + ASSERT_TRUE(its_manager->is_enabled()); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid_valid = utility::create_uds_client(invalid_uid, valid_gid, host_address); + vsomeip_sec_client_t its_sec_client_valid_invalid = utility::create_uds_client(valid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + // is expected check_credentials method always return true + //invalid uid and gid + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_invalid)); + + //invalid uid and valid gid + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_invalid_valid)); + + //valid uid and invalid gid + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_valid_invalid)); + + //valid uid and gid + EXPECT_TRUE(its_manager->check_credentials(client, &its_sec_client_valid)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_routing_credentials.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_routing_credentials.cpp new file mode 100644 index 00000000000..0112cadb5b3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_check_routing_credentials.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +vsomeip_v3::uid_t invalid_uid = 1; +vsomeip_v3::uid_t valid_uid = 4003017; +vsomeip_v3::gid_t invalid_gid = 1; +vsomeip_v3::gid_t valid_gid = 5002; +vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(check_routing_credentials, check_policies_loaded) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + for (const auto& e : policy_elements) + security->load(e, false); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_valid_uid_invalid_gid = utility::create_uds_client(valid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid_valid_gid = utility::create_uds_client(invalid_uid, valid_gid, host_address); + + //valid uid and gid -> the check must return true + EXPECT_TRUE(security->check_routing_credentials(&its_sec_client_valid)); + + //invalid gid and valid gid -> the check must return false + EXPECT_FALSE(security->check_routing_credentials(&its_sec_client_valid_uid_invalid_gid)); + + //invalid uid and valid gid -> the check must return false + EXPECT_FALSE(security->check_routing_credentials(&its_sec_client_invalid_uid_valid_gid)); + + //invalid uid and gid -> the check must return false + EXPECT_FALSE(security->check_routing_credentials(&its_sec_client_invalid)); +} + +// check_routing_credentials with policies loaded in lazy mode +// vsomeip's security implementation can be put in a so called 'Audit Mode' where +// all security violations will be logged but allowed. +// To activate the 'Audit Mode' the 'security' object has to be included in the +// json file but the 'check_routing_credentials' switch has to be set to false. +TEST(check_routing_credentials, check_policies_loaded_lazy_load) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + // load policies in lazy mode so that check_routing_credentials is false + for (const auto& e : policy_elements) + security->load(e, true); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(valid_uid, valid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_valid_uid_invalid_gid = utility::create_uds_client(valid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid_valid_gid = utility::create_uds_client(invalid_uid, valid_gid, host_address); + + //expect check_routing_credentials_ false so method always returns true + EXPECT_TRUE(security->check_routing_credentials(&its_sec_client_valid)); + EXPECT_TRUE(security->check_routing_credentials(&its_sec_client_valid_uid_invalid_gid)); + EXPECT_TRUE(security->check_routing_credentials(&its_sec_client_invalid_uid_valid_gid)); + EXPECT_TRUE(security->check_routing_credentials(&its_sec_client_invalid)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_client_to_sec_client_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_client_to_sec_client_mapping.cpp new file mode 100644 index 00000000000..c47d404e37f --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_client_to_sec_client_mapping.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +vsomeip_v3::client_t client = 10; +vsomeip_v3::client_t alternate_client = 11; +vsomeip_v3::uid_t uid_1 = 4003030; +vsomeip_v3::gid_t gid_1 = 4003032; +vsomeip_v3::uid_t uid_2 = 1; +vsomeip_v3::gid_t gid_2 = 1; +vsomeip_v3::uid_t uid_3 = 2; +vsomeip_v3::gid_t gid_3 = 2; +vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(get_client_to_sec_client_mapping, test) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid_1 = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_2 = utility::create_uds_client(uid_2, gid_2, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_3 = utility::create_uds_client(uid_3, gid_3, host_address); + + // Client and uid_gid should not be stored yet. + EXPECT_FALSE(security->get_client_to_sec_client_mapping(client, its_sec_client_uid_gid_1)); + + // Add client and uid_gid mappings. + security->store_client_to_sec_client_mapping(client, &its_sec_client_uid_gid_1); + + // uid_gid and uid_gid_2 should not be equal. + EXPECT_NE(its_sec_client_uid_gid_1.group, its_sec_client_uid_gid_2.group); + EXPECT_NE(its_sec_client_uid_gid_1.user, its_sec_client_uid_gid_2.user); + + // Client and uid_gid mapping should be returned. + EXPECT_TRUE(security->get_client_to_sec_client_mapping(client, its_sec_client_uid_gid_2)); + + // uid_gid and uid_gid_2 should be equal if get was successful. + EXPECT_EQ(its_sec_client_uid_gid_1.group, its_sec_client_uid_gid_2.group); + EXPECT_EQ(its_sec_client_uid_gid_1.user, its_sec_client_uid_gid_2.user); + + // Alternate_client is not stored, this should return false. + EXPECT_FALSE(security->get_client_to_sec_client_mapping(alternate_client, its_sec_client_uid_gid_1)); + + // Add alternate client and uid_gid mappings. + security->store_client_to_sec_client_mapping(alternate_client, &its_sec_client_uid_gid_1); + + // uid_gid and uid_gid_3 should not be equal. + EXPECT_NE(its_sec_client_uid_gid_1.group, its_sec_client_uid_gid_3.group); + EXPECT_NE(its_sec_client_uid_gid_1.user, its_sec_client_uid_gid_3.user); + + // Alternate client and uid_gid mapping should be returned. + EXPECT_TRUE(security->get_client_to_sec_client_mapping(alternate_client, its_sec_client_uid_gid_3)); + + // uid_gid and uid_gid_3 should be equal if get was successful. + EXPECT_EQ(its_sec_client_uid_gid_1.group, its_sec_client_uid_gid_3.group); + EXPECT_EQ(its_sec_client_uid_gid_1.user, its_sec_client_uid_gid_3.user); + } diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_clients.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_clients.cpp new file mode 100644 index 00000000000..49a4b09c184 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_clients.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +std::unordered_set<vsomeip_v3::client_t> clients; +std::unordered_set<vsomeip_v3::client_t> local_clients; +vsomeip_v3::client_t client_1 = 10; +vsomeip_v3::client_t client_2 = 11; +vsomeip_v3::client_t client_3 = 12; +vsomeip_v3::uid_t uid = 4003030; +vsomeip_v3::gid_t gid = 4003032; +vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(get_clients, test) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client_uid_gid = utility::create_uds_client(uid, gid, host_address); + + // Local_clients has now one client(10). + local_clients.insert(client_1); + + // Clients should be empty. + EXPECT_TRUE(clients.empty()); + + // Should do nothing because there is not a client to uid_gid mapping yet. + security->get_clients(uid, gid, clients); + + // clients should still be empty. + EXPECT_TRUE(clients.empty()); + + // Stores client to uid_gid_mapping. + security->store_client_to_sec_client_mapping(client_1, &its_sec_client_uid_gid); + security->get_clients(uid, gid, clients); + + // Clients and local_clients should be equal and have the same client(10). + EXPECT_EQ(clients, local_clients); + + // Repeat with two more clients. + security->store_client_to_sec_client_mapping(client_2, &its_sec_client_uid_gid); + security->store_client_to_sec_client_mapping(client_3, &its_sec_client_uid_gid); + + local_clients.insert(client_2); + local_clients.insert(client_3); + + security->get_clients(uid, gid, clients); + + // Clients and local_clients should be equal and have the same 3 clients(10,11,12). + EXPECT_EQ(clients, local_clients); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_sec_client_to_clients_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_sec_client_to_clients_mapping.cpp new file mode 100644 index 00000000000..ad2986ded60 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_get_sec_client_to_clients_mapping.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace{ +vsomeip_v3::client_t client = 10; +vsomeip_v3::uid_t uid_1 = 4003030; +vsomeip_v3::gid_t gid_1 = 4003032; +vsomeip_v3::uid_t uid_2 = 1; +vsomeip_v3::gid_t gid_2 = 1; +vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(get_sec_client_to_clients_mapping, test) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + std::set<vsomeip_v3::client_t> clients_1; + clients_1.insert(client); + + vsomeip_sec_client_t its_sec_client_uid_gid = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_uid_gid_alternate = utility::create_uds_client(uid_2, gid_2, host_address); + + // Client and uid_gid should not be stored yet. + EXPECT_FALSE(security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid, clients_1)); + + // Add client and uid_gid mappings. + security->store_sec_client_to_client_mapping(&its_sec_client_uid_gid, client); + + std::set<vsomeip_v3::client_t> clients_2; + + // Clients and clients_2 should not be equal. + EXPECT_NE(clients_1, clients_2); + + // Client and uid_gid mapping should be returned. + EXPECT_TRUE(security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid, clients_2)); + + // Clients and clients_2 should be equal if get was successful. + EXPECT_EQ(clients_1, clients_2); + + // Alternate_uid_gid is not stored, this should return false. + EXPECT_FALSE(security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid_alternate, clients_1)); + + // Add alternate client and uid_gid mappings. + security->store_sec_client_to_client_mapping(&its_sec_client_uid_gid_alternate, client); + + std::set<vsomeip_v3::client_t> clients_3; + + // Clients and clients_3 should not be equal. + EXPECT_NE(clients_1, clients_3); + + // Alternate client and uid_gid mapping should be returned. + EXPECT_TRUE(security->get_sec_client_to_clients_mapping(&its_sec_client_uid_gid_alternate, clients_3)); + + // Clients and clients_3 should be equal if get was successful. + EXPECT_EQ(clients_1, clients_3); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_client_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_client_allowed.cpp new file mode 100644 index 00000000000..bd6f72f073c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_client_allowed.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include "gtest/gtest.h" +#include <common/utility.hpp> + +namespace { + vsomeip_v3::uid_t uid_1 = 4003031; + vsomeip_v3::gid_t gid_1 = 4003031; + vsomeip_sec_ip_addr_t host_address = 0; + vsomeip_v3::service_t service_1 = 0xf913; + + vsomeip_v3::service_t service_2 = 0x41; // service not defined in policies + + vsomeip_v3::instance_t instance = 0x03; + vsomeip_v3::instance_t instance_2 = 0x04; + vsomeip_v3::method_t method = 0x04; + vsomeip_v3::method_t method_2 = 0x05; + + vsomeip_v3::gid_t invalid_uid = 1; + vsomeip_v3::gid_t invalid_gid = 1; + vsomeip_v3::uid_t ANY_UID = 0xFFFFFFFF; + vsomeip_v3::gid_t ANY_GID = 0xFFFFFFFF; + + vsomeip_v3::gid_t deny_uid = 9999; + vsomeip_v3::gid_t deny_gid = 9999; + vsomeip_v3::service_t deny_service = 0x40; +} + +TEST(is_client_allowed_test, check_no_policies_loaded) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + //no policies loaded -> is_client_allowed must return true + ASSERT_FALSE(its_manager->is_enabled()); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_invalid, service_1, instance, method)); +} + +TEST(is_client_allowed_test, check_policies_loaded) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // check if the policies are loaded and check_credentials_ variable are true + ASSERT_TRUE(its_manager->is_enabled()); + ASSERT_FALSE(its_manager->is_audit()); + + // create security clients + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid = utility::create_uds_client(invalid_uid, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid_gid = utility::create_uds_client(uid_1, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_any = utility::create_uds_client(ANY_UID, ANY_GID, host_address); + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + //valid credential for valid service / istance / method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method)); + + // test is_client_allowed_cache_, request with the same credentials and service / instance / method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method)); + + // test is_client_allowed_cache_, request with the same credentials and service but with a different instance or method + // is_client_allowed return true because it's define ANY_INSTANCE and ANY_METHOD in the policy + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance_2, method)); + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method_2)); + + //invalid credential for the service / istance / method + EXPECT_FALSE(its_manager->is_client_allowed(&its_sec_client_invalid_uid, service_1, instance, method)); + EXPECT_FALSE(its_manager->is_client_allowed(&its_sec_client_invalid_gid, service_1, instance, method)); + + //ANY_UID and ANY_GID + EXPECT_FALSE(its_manager->is_client_allowed(&its_sec_client_any, service_1, instance, method)); + + // test deny client + // deny client with credentials for the service + EXPECT_FALSE(its_manager->is_client_allowed(&its_sec_client_deny, deny_service, instance, method)); + // credencials exists in deny policy, but not for that service + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_deny, service_2, instance, method)); +} + + +// is_client_allowed with policies loaded but in audit mode +// vsomeip's security implementation can be put in a so called 'Audit Mode' where +// all security violations will be logged but allowed. +// To activate the 'Audit Mode' the 'security' object has to be included in the +// json file but the 'check_credentials' switch has to be set to false. + TEST(is_client_allowed_test, check_policies_loaded_in_audit_mode) { + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + //force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + //check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + utility::force_check_credentials(policy_elements, "false"); + + for (const auto& e : policy_elements) { + its_manager->load(e, false); + } + + // check if the policies are loaded and check_credentials_ variable are false + ASSERT_TRUE(its_manager->is_enabled()); + ASSERT_TRUE(its_manager->is_audit()); + + // create security clients + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid = utility::create_uds_client(invalid_uid, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid_gid = utility::create_uds_client(uid_1, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_any = utility::create_uds_client(ANY_UID, ANY_GID, host_address); + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + + // is expected is_client_allowed method always returns true + // valid credential for valid service / istance / method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method)); + + // test is_client_allowed_cache_, request with the same credentials and service / instance / method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method)); + + // test is_client_allowed_cache_, request with the same credentials and service but with a different instance or method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance_2, method)); + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client, service_1, instance, method_2)); + + // invalid credential for the service / istance / method + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_invalid_uid, service_1, instance, method)); + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_invalid_gid, service_1, instance, method)); + + // ANY_UID and ANY_GID + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_any, service_1, instance, method)); + + // test deny client + // deny client with credentials for the service + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_deny, deny_service, instance, method)); + // credencials exists in deny policy, but not for that service + EXPECT_TRUE(its_manager->is_client_allowed(&its_sec_client_deny, service_2, instance, method)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_offer_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_offer_allowed.cpp new file mode 100644 index 00000000000..005eaf007d4 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_offer_allowed.cpp @@ -0,0 +1,154 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> +namespace{ + +vsomeip_v3::uid_t uid_1 = 4003016; +vsomeip_v3::gid_t gid_1 = 4003016; +vsomeip_sec_ip_addr_t host_address = 0; +vsomeip_v3::service_t service_1 = 0xf8c2; + +vsomeip_v3::service_t deny_service = 0x40; + +vsomeip_v3::instance_t instance = 0x03; +vsomeip_v3::instance_t any_instance = 0xfffe; + +vsomeip_v3::uid_t invalid_uid = 1; +vsomeip_v3::gid_t invalid_gid = 1; +vsomeip_v3::uid_t ANY_UID = 0xFFFFFFFF; +vsomeip_v3::gid_t ANY_GID = 0xFFFFFFFF; + +vsomeip_v3::gid_t deny_uid = 9000; +vsomeip_v3::gid_t deny_gid = 9000; +} + +TEST(is_offer_allowed, check_no_policies_loaded) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + ASSERT_FALSE(security->is_enabled()); + + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + + // no policies loaded -> is_offer_allowed must return true + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_invalid, service_1, instance)); +} + +TEST(is_offer_allowed, check_policies_loaded) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + // check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + for (const auto &e : policy_elements) + { + security->load(e, false); + } + + // check if the policies are loaded and check_credentials_ variable are true + ASSERT_TRUE(security->is_enabled()); + ASSERT_FALSE(security->is_audit()); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_valid_uid_invalid_gid = utility::create_uds_client(uid_1, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid_valid_gid = utility::create_uds_client(invalid_uid, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + vsomeip_sec_client_t its_sec_client_any = utility::create_uds_client(ANY_UID, ANY_GID, host_address); + + // valid credential for valid service / instance + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_valid, service_1, instance)); + + // request with the same credentials and service but with a different instance + // is_offer_allowed return true because it's define ANY_INSTANCE in the policy + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_valid, service_1, any_instance)); + + // invalid credential for the service / instance + EXPECT_FALSE(security->is_offer_allowed(&its_sec_client_invalid_uid_valid_gid, service_1, instance)); + EXPECT_FALSE(security->is_offer_allowed(&its_sec_client_valid_uid_invalid_gid, service_1, instance)); + EXPECT_FALSE(security->is_offer_allowed(&its_sec_client_invalid, service_1, instance)); + + // test deny offer + // deny client with credentials for the service + EXPECT_FALSE(security->is_offer_allowed(&its_sec_client_deny, deny_service, instance)); + // credentials exists in deny policy, but not for that service + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_deny, service_1, instance)); + + // ANY_UID and ANY_GID + EXPECT_FALSE(security->is_offer_allowed(&its_sec_client_any, service_1, instance)); +} + +// is_offer_allowed with policies loaded but in audit mode +// vsomeip's security implementation can be put in a so called 'Audit Mode' where +// all security violations will be logged but allowed. +// To activate the 'Audit Mode' the 'security' object has to be included in the +// json file but the 'check_credentials' switch has to be set to false. + +TEST(is_offer_allowed, check_policies_loaded_in_audit_mode) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // create security clients + vsomeip_sec_client_t its_sec_client_valid = utility::create_uds_client(uid_1, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_invalid = utility::create_uds_client(invalid_uid, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_valid_uid_invalid_gid = utility::create_uds_client(uid_1, invalid_gid, host_address); + vsomeip_sec_client_t its_sec_client_invalid_uid_valid_gid = utility::create_uds_client(invalid_uid, gid_1, host_address); + vsomeip_sec_client_t its_sec_client_deny = utility::create_uds_client(deny_uid, deny_gid, host_address); + vsomeip_sec_client_t its_sec_client_any = utility::create_uds_client(ANY_UID, ANY_GID, host_address); + + // force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), policy_elements, its_failed); + + // check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + utility::force_check_credentials(policy_elements, "false"); + + for (const auto &e : policy_elements) + { + security->load(e, false); + } + + // check if the policies are loaded and check_credentials_ variable are true + ASSERT_TRUE(security->is_enabled()); + ASSERT_TRUE(security->is_audit()); + + // valid credential for valid service / instance + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_valid, service_1, instance)); + + // request with the same credentials and service but with a different instance + // is_offer_allowed return true because it's define ANY_INSTANCE in the policy + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_valid, service_1, any_instance)); + + // invalid credential for the service / instance + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_invalid_uid_valid_gid, service_1, instance)); + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_valid_uid_invalid_gid, service_1, instance)); + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_invalid, service_1, instance)); + + // test deny offer + // deny client with credentials for the service + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_deny, deny_service, instance)); + // credentials exists in deny policy, but not for that service + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_deny, service_1, instance)); + + // ANY_UID and ANY_GID + EXPECT_TRUE(security->is_offer_allowed(&its_sec_client_any, service_1, instance)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_policy_update_allowed.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_policy_update_allowed.cpp new file mode 100644 index 00000000000..8bb57404ce3 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_is_policy_update_allowed.cpp @@ -0,0 +1,223 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <iostream> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; + +vsomeip_v3::uid_t valid_uid { 0 }; +vsomeip_v3::uid_t invalid_uid { 1234567 }; + +vsomeip_v3::gid_t valid_gid { 0 }; + +vsomeip_v3::service_t valid_service { 0xf913 }; +vsomeip_v3::service_t invalid_service { 0x41 }; +} + +#ifndef __QNX__ +TEST(is_policy_update_allowed, check_whitelist_disabled) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the configuration into the security. + ASSERT_GT(policy_elements.size(), 0) << "Failed to fetch policy elements!"; + const bool check_whitelist { false }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + // NO REQUESTS IN POLICY ---------------------------------------------------------------------// + + EXPECT_TRUE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to allow policy update with invalid user id when check_whitelist is " + "disabled!"; + + EXPECT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to allow policy update with valid user id when check_whitelist is " + "disabled!"; + + // ONLY VALID REQUESTS IN POLICY -------------------------------------------------------------// + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, boost::icl::interval_set<vsomeip::method_t>> + its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + valid_service, valid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + EXPECT_TRUE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to allow policy update with invalid user id and valid request when " + "check_whitelist is disabled!"; + + EXPECT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to allow policy update with valid user id and valid request when " + "check_whitelist is disabled!"; + + // INVALID REQUESTS IN POLICY ----------------------------------------------------------------// + + // Add a invalid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + invalid_service, invalid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + EXPECT_TRUE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to allow policy update with invalid user id and invalid request when " + "check_whitelist is disabled!"; + + EXPECT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to allow policy update with valid user id and invalid request when " + "check_whitelist is disabled!"; +} + +TEST(is_policy_update_allowed, check_whitelist_enabled) +{ + // Test object. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the policy into the security. + ASSERT_GT(policy_elements.size(), 0) << "Failed to fetch policy elements!"; + const bool check_whitelist { true }; + utility::add_security_whitelist(policy_elements.at(0), check_whitelist); + security->load(policy_elements.at(0), false); + + // Create policy credentials. + boost::icl::discrete_interval<uid_t> its_uids(valid_uid, valid_uid); + boost::icl::interval_set<gid_t> its_gids; + its_gids.insert(boost::icl::interval<gid_t>::closed(valid_gid, valid_gid)); + + // Create a policy. + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + policy->credentials_ += std::make_pair(its_uids, its_gids); + policy->allow_who_ = true; + policy->allow_what_ = true; + + // NO REQUESTS IN POLICY ---------------------------------------------------------------------// + + EXPECT_FALSE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to deny policy update with invalid user id!"; + + EXPECT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to allow policy update with valid user id!"; + + // ONLY VALID REQUESTS IN POLICY -------------------------------------------------------------// + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, boost::icl::interval_set<vsomeip::method_t>> + its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add valid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + valid_service, valid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + EXPECT_FALSE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to deny policy update with invalid user id and valid request!"; + + EXPECT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to allow policy update with valid user id and valid request!"; + + // INVALID REQUESTS IN POLICY ----------------------------------------------------------------// + + // Add invalid request to the policy. + policy->requests_ += std::make_pair( + boost::icl::discrete_interval<vsomeip::service_t>( + invalid_service, invalid_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + EXPECT_FALSE(security->is_policy_update_allowed(invalid_uid, policy)) + << "Failed to deny policy update with invalid user id and invalid request!"; + + EXPECT_FALSE(security->is_policy_update_allowed(valid_uid, policy)) + << "Failed to deny policy update with valid user id and invalid request!"; +} +#endif + +TEST(is_policy_update_allowed, null_policy) +{ + // Test objects. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + std::shared_ptr<vsomeip_v3::policy> policy = nullptr; + + // NO POLICIES LOADED ------------------------------------------------------------------------// + + ASSERT_EXIT((security->is_policy_update_allowed(0, policy), exit(0)), + testing::ExitedWithCode(0), ".*") + << "Could not handle a nullptr when no policies are loaded!"; + + EXPECT_TRUE(security->is_policy_update_allowed(0, policy)) + << "Denied update of policy when security whitelist is not loaded!"; + + // LOADED POLICY W/O SECURITY WHITELIST ------------------------------------------------------// + + // Get some configurations. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Load the policy into the security. + ASSERT_GT(policy_elements.size(), 0) << "Failed to fetch policy elements!"; + security->load(policy_elements.at(0), false); + + ASSERT_EXIT((security->is_policy_update_allowed(0, policy), exit(0)), + testing::ExitedWithCode(0), ".*") + << "Could not handle a nullptr when a policy without a security whitelist was loaded!"; + + EXPECT_TRUE(security->is_policy_update_allowed(0, policy)) + << "Denied update of policy when security whitelist is not loaded!"; + + // LOADED POLICY W/ SECURITY WHITELIST -------------------------------------------------------// + + // Add a security whitelist to the policy. + + utility::add_security_whitelist(policy_elements.at(0), true); + + security->load(policy_elements.at(0), false); + + ASSERT_EXIT((security->is_policy_update_allowed(0, policy), exit(0)), + testing::ExitedWithCode(0), ".*") + << "Could not handle a nullptr when a policy with a security whitelist was loaded!"; + + EXPECT_FALSE(security->is_policy_update_allowed(0, policy)) + << "Allowed update of invalid policy!"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load.cpp new file mode 100644 index 00000000000..793d77f5795 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <memory> + +#include <common/utility.hpp> + +namespace +{ + std::string configuration_file{"/vsomeip/0_0/vsomeip_security.json"}; +} + +TEST(load, No_element) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + // Set element + std::vector<vsomeip_v3::configuration_element> empty_element = {}; // elements + std::vector<vsomeip_v3::configuration_element> full_element = {}; + + // Check element and full element size init =zero + ASSERT_TRUE(empty_element.size() == 0) << " Initial element size is not zero"; + ASSERT_TRUE(full_element.size() == 0) << " Initial full element size is not zero"; + + // After load try again and check size + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), + full_element, its_failed); // check if this is load without for cicle + + // Load each e into policy_elements + for (const auto &e : full_element) + { + its_manager->load(e, false); // for each e in policy_elements vector load e + }; + + // Check size of full_element after load >0 + ASSERT_TRUE(full_element.size() > 0) << "Full element size is zero after load, should be >0 since policy was loaded"; + + // Compare full element greater than element + ASSERT_GT(full_element.size(), empty_element.size()) << "Full element is not greater than unit element"; +} + +TEST(load, _lazy_load) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + // Set element and lazy load + std::vector<vsomeip_v3::configuration_element> element = {}; + const bool lazy_load = true; + + // Load + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), + element, its_failed); + + // Apply load function for each e into element and check if lazy load=true for each e loaded + for (const auto &e : element) + { + its_manager->load(e, lazy_load); + EXPECT_EQ(lazy_load, true) << "Lazy load not equal true"; + }; + + // Test first element without for cycle + const vsomeip_v3::configuration_element &e = element.at(0); + its_manager->load(e, lazy_load); + EXPECT_EQ(lazy_load, true) << "Lazy load not equal true"; +} + +TEST(load, policy_enabled_and_check_credentials) +{ + // Test object path + std::unique_ptr<vsomeip_v3::policy_manager_impl> its_manager(new vsomeip_v3::policy_manager_impl); + + // Set element and lazy load + std::vector<vsomeip_v3::configuration_element> element = {}; + + // Check values for policy enabled and check_credentials before load policy + // No policies loaded -> check credentials will return false. policy_enabled is private so needs to be check like this + ASSERT_TRUE(its_manager->is_audit()) << "policies were loaded. policy_enable should be true"; + ASSERT_FALSE(its_manager->is_enabled()) << "policies were loaded. check_credentials should be false"; + + // Load full + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir( + utility::get_policies_path(), dir_skip), + element, its_failed); + + // Load each e into policy_elements + for (const auto &e : element) + { + its_manager->load(e, false); // for each e in policy_elements vector load e + }; + + // Check policies loaded after + ASSERT_FALSE(its_manager->is_audit()) << "policies were loaded. policy_enable should be false"; + ASSERT_TRUE(its_manager->is_enabled()) << "policies were loaded. check_credentials should be true"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_policies.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_policies.cpp new file mode 100644 index 00000000000..6bcb7e62953 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_policies.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; +vsomeip_v3::uid_t valid_uid = 4002200; +vsomeip_v3::gid_t valid_gid = 4003014; +} + +// Since this set of tests check a private method, there is the need to indirectly change the +// parameters used by load_policies, and check its changes using other methods. +// The remove_security_policy method checks if there is any loaded policy. +// The is_audit method checks the check_credentials value. +// No test was created for allow_remote_clients because it was inacessible. + +TEST(load_policies, any_policies_present) +{ + // LOADED POLICIES --------------------------------------------------------------------------// + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Check if the load worked. + ASSERT_EQ(its_failed.size(), 0); + + // Using load function to indirectly call load_policies. + security->load(policy_elements.at(0)); + + // Check that the policies were loaded from the file by trying to remove one of the loaded + // policies. + // If the policy is present, remove_security_policy returns true. + ASSERT_TRUE(security->remove_security_policy(valid_uid,valid_gid)) + << "Trying to remove a policy that is supposed to exist, but doesn't"; + + // POLICIES NOT LOADED -----------------------------------------------------------------------// + // Remove all the policies from the file. + policy_elements.at(0).tree_.get_child("security").erase("policies"); + + // Using load function to indirectly call load_policies. + security->load(policy_elements.at(0)); + + // Check that no policies were loaded. + ASSERT_FALSE(security->remove_security_policy(valid_uid,valid_gid)) + << "Trying to remove a policy should not exist, but it exists"; +} + +TEST(load_policies, check_credentials) +{ + // CHECK CREDENTIALS NOT SET -----------------------------------------------------------------// + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies without the check credentials value set. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Check if the load worked. + ASSERT_EQ(its_failed.size(), 0); + + security->load(policy_elements.at(0)); + + // Check that the check_credentials value was not set, using the is_audit method. + ASSERT_TRUE(security->is_audit()) + << "Check credentials value should be false when no value is loaded"; + + // CHECK CREDENTIALS SET TRUE ----------------------------------------------------------------// + + // Load the check credentials value as false. + bool check_credentials_value {true}; + policy_elements.at(0).tree_.add<bool>("security.check_credentials", check_credentials_value); + security->load(policy_elements.at(0)); + + // Check that the check_credentials flag was not set internally, using the is_audit method. + ASSERT_FALSE(security->is_audit()) + << "Check credentials flag should be true when the check_credential value is loaded as" + "true"; + + // CHECK CREDENTIALS SET FALSE ---------------------------------------------------------------// + + // Load the check credentials value as false. + check_credentials_value = false; + policy_elements.at(0).tree_.put<bool>("security.check_credentials", check_credentials_value); + security->load(policy_elements.at(0)); + + // Check that the check_credentials flag was set false, using the is_audit method. + ASSERT_TRUE(security->is_audit()) + << "Check credentials flag should be false when the check_credential value is loaded as" + "false"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_policy_extensions.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_policy_extensions.cpp new file mode 100644 index 00000000000..1efb14fff61 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_policy_extensions.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <common/utility.hpp> +#include <gtest/gtest.h> +#include <memory> + +// create valid and invalid user credentials +namespace +{ + std::string configuration_file{ + "/vsomeip/vsomeip_policy_extensions.json"}; // set configuration file policy + +} // namespace + +TEST(load_security_policy_extensions, no_configuration_element) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> element; + std::vector<vsomeip_v3::configuration_element> full_element; + + // Save init size values. + auto element_size = element.size(); + auto full_element_size = full_element.size(); + + // Check element and full element size init =zero. + ASSERT_TRUE(element.size() == 0) << " Initial element size is not zero"; + + // After load try again and check size. + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data( + utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + full_element, its_failed); + + // Load each e into policy_elements. + for (const auto &e : full_element) + { + security->load(e, false); + } + + ASSERT_EQ(element_size, full_element_size) + << "Policy element before load is not zero. Size = " << element_size + << " And size after load = " << full_element_size; + + // Check size of full_element after load >0 + ASSERT_TRUE(full_element.size() > 0) + << "Full element size is zero after load, should be >0 since policy was " + "loaded"; +} + +TEST(load_security_policy_extensions, configuration_element) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<vsomeip_v3::configuration_element> element; + + // Force load of policies. + std::set<std::string> its_failed; + std::vector<std::string> dir_skip; + utility::read_data( + utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + policy_elements, its_failed); + + // Load each e into policy_elements. + for (const auto &e : policy_elements) + { + security->load(e, false); + } + + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_GT(policy_elements.size(), element.size()) << "Policies did not load"; +} + +TEST(load_security_policy_extensions, is_policy_extension_loaded) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> policy_elements; + + // Force Load of policies. + std::set<std::string> its_failed; + std::set<std::string> input{utility::get_policies_path() + + configuration_file}; + utility::read_data(input, policy_elements, its_failed); + + // Load policies. + security->load(policy_elements.at(0)); + + // Check JSON container string. + std::string policy_extension_container{"android-rse"}; + + // Set extension loaded. + bool loaded_extension = true; + security->set_is_policy_extension_loaded(policy_extension_container, loaded_extension); + + // Print path for "android-rse". + std::cout << "Policy Extension Path: " << security->get_policy_extension_path(policy_extension_container) << std::endl; + + // Check if policy extension is loaded and path found. + ASSERT_EQ(security->is_policy_extension_loaded(policy_extension_container), vsomeip_v3::policy_manager_impl::policy_loaded_e:: + POLICY_PATH_FOUND_AND_LOADED); +} + +TEST(load_security_policy_extensions, is_policy_extension_NOT_loaded) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Set element. + std::vector<vsomeip_v3::configuration_element> policy_elements; + + // Force load of policies and read data. + std::set<std::string> its_failed; + std::set<std::string> input{utility::get_policies_path() + + configuration_file}; + utility::read_data(input, policy_elements, its_failed); + + // Load Policies. + security->load(policy_elements.at(0)); + + // Check JSON container string. + std::string policy_extension_container{"android-rse"}; + + // Set extension as not loaded. + bool loaded_extension = false; + security->set_is_policy_extension_loaded(policy_extension_container, loaded_extension); + + // Print path for "android-rse". + std::cout << "Policy Extension Path: " << security->get_policy_extension_path(policy_extension_container) << std::endl; + + // Check if policy extension is loaded and path found. + ASSERT_EQ(security->is_policy_extension_loaded(policy_extension_container), vsomeip_v3::policy_manager_impl::policy_loaded_e:: + POLICY_PATH_FOUND_AND_NOT_LOADED); +} + +TEST(load_security_policy_extensions, is_policy_extension_NOT_found) +{ + // Test object path. + std::unique_ptr<vsomeip_v3::policy_manager_impl> security{ + new vsomeip_v3::policy_manager_impl}; + + // Check path not found and extension not loaded. + ASSERT_EQ(security->is_policy_extension_loaded(""), vsomeip_v3::policy_manager_impl::policy_loaded_e::POLICY_PATH_INEXISTENT); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_update_whitelist.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_update_whitelist.cpp new file mode 100644 index 00000000000..94b52c7f390 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_load_security_update_whitelist.cpp @@ -0,0 +1,218 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace { +std::string configuration_file { "/vsomeip/0_0/vsomeip_security.json" }; +vsomeip_v3::service_t valid_service_id = 0xf91f; +vsomeip_v3::service_t invalid_service_id = 0xf923; +vsomeip_v3::uid_t valid_uid = 4017205; +vsomeip_v3::uid_t invalid_uid = 111111; +} + +// Since this set of tests check a private method, there is the need to indirectly change the +// parameters used by load_security_update_whitelist, and check its changes using other methods. +// The is_policy_removal_allowed method checks if a selected uid is present in the whitelist. +// The is_policy_update_allowed method checks if a selected service_id is present in the whitelist. + +TEST(load_security_update_whitelist, check_uids) +{ + // LOADED POLICY W/O UIDS ON SECURITY WHITELIST ---------------------------------------------// + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Check if the load worked. + ASSERT_EQ(its_failed.size(), 0); + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with an empty list of user uids. + std::vector<vsomeip_v3::uid_t> user_ids; + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + security->load(policy_elements.at(0)); + + // Check that the valid and invalid uids are not present in the whitelist by calling a method + // that verifies that condition. + ASSERT_FALSE(security->is_policy_removal_allowed(valid_uid)) + << "The whitelist unexpectedly holds a valid uid"; + + ASSERT_FALSE(security->is_policy_removal_allowed(invalid_uid)) + << "The whitelist unexpectedly holds an invalid uid"; + + // LOADED POLICY WITH UIDS ON SECURITY WHITELIST ---------------------------------------------// + utility::get_policy_uids(policy_elements.at(0), user_ids); + + // Add a security whitelist with list of user uids loaded. + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + security->load(policy_elements.at(0)); + + // Check that the valid and invalid uids are not present in the whitelist by calling a method + // that verifies that condition. + ASSERT_TRUE(security->is_policy_removal_allowed(valid_uid)) + << "The whitelist expected to hold a valid uid"; + + ASSERT_FALSE(security->is_policy_removal_allowed(invalid_uid)) + << "The whitelist unexpectedly holds an invalid uid"; +} + +TEST(load_security_update_whitelist, check_service_ids) +{ + // LOADED POLICY W/O SERVICE IDS ON SECURITY WHITELIST -------------------------------------// + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Check if the load worked. + ASSERT_EQ(its_failed.size(), 0); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + // Add a security whitelist with an empty list of service ids. + std::vector<vsomeip_v3::service_t> services; + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + // Using load function to indirectly call load_security_update_whitelist. + security->load(policy_elements.at(0)); + + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + + vsomeip::service_t its_service(valid_service_id); + vsomeip::service_t its_invalid_service(invalid_service_id); + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, boost::icl::interval_set<vsomeip::method_t>> + its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy + policy->requests_ += + std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_service, its_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + // Check its presence using the is_policy_update_allowed method. + ASSERT_FALSE(security->is_policy_update_allowed(valid_uid, policy)) + << "The whitelist unexpectedly holds a valid service_id"; + + // Add an invalid request to the policy + policy->requests_ += std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_invalid_service, its_invalid_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + + // Check its presence using the is_policy_update_allowed method. + ASSERT_FALSE(security->is_policy_update_allowed(valid_uid, policy)) + << "The whitelist unexpectedly holds an invalid service_id"; + + // LOADED POLICY WITH SERVICE IDS ON SECURITY WHITELIST --------------------------------------// + utility::get_policy_services(policy_elements.at(0), services); + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, true); + + security->load(policy_elements.at(0)); + + // Reset the policies pointer to add a correct serviceid and an incorrect one. + policy->requests_.clear(); + + // Add a valid request to the policy. + policy->requests_ += + std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_service, its_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + // Check its presence using the is_policy_update_allowed method. + ASSERT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "The whitelist expected to hold a valid service_id"; + + // Add an invalid request to the policy. + policy->requests_ += std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_invalid_service, its_invalid_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + + // Check its presence using the is_policy_update_allowed method. + ASSERT_FALSE(security->is_policy_update_allowed(invalid_uid, policy)) + << "The whitelist unexpectedly holds an invalid service_id"; +} + +TEST(load_security_update_whitelist, check_whitelist_disabled) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // Force load of some policies. + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::set<std::string> input { utility::get_policies_path() + configuration_file }; + utility::read_data(input, policy_elements, its_failed); + + // Check if the load worked. + ASSERT_EQ(its_failed.size(), 0); + + std::vector<vsomeip_v3::uid_t> user_ids; + utility::get_policy_uids(policy_elements.at(0), user_ids); + + std::vector<vsomeip_v3::service_t> services; + utility::get_policy_services(policy_elements.at(0), services); + + // Add a security whitelist with check_whitelist disabled. + utility::add_security_whitelist(policy_elements.at(0), user_ids, services, false); + + security->load(policy_elements.at(0)); + + std::shared_ptr<vsomeip::policy> policy(std::make_shared<vsomeip::policy>()); + + vsomeip::service_t its_service(valid_service_id); + vsomeip::service_t its_invalid_service(invalid_service_id); + + boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2); + boost::icl::interval_set<vsomeip::method_t> its_methods; + its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2)); + boost::icl::interval_map<vsomeip::instance_t, boost::icl::interval_set<vsomeip::method_t>> + its_instances_methods; + its_instances_methods += std::make_pair(its_instances, its_methods); + + // Add a valid request to the policy. + policy->requests_ += + std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_service, its_service, boost::icl::interval_bounds::closed()), + its_instances_methods); + + ASSERT_TRUE(security->is_policy_removal_allowed(valid_uid)) + << "The whitelist is disabled, a valid uid should be allowed to be removed"; + + ASSERT_TRUE(security->is_policy_removal_allowed(invalid_uid)) + << "The whitelist is disabled, an invalid uid should be allowed to be removed"; + + ASSERT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "The whitelist is disabled, a valid service_id should be allowed to be updated"; + + // Add an invalid request to the policy. + policy->requests_ += std::make_pair(boost::icl::discrete_interval<vsomeip::service_t>( + its_invalid_service, its_invalid_service, + boost::icl::interval_bounds::closed()), + its_instances_methods); + + ASSERT_TRUE(security->is_policy_update_allowed(valid_uid, policy)) + << "The whitelist is disabled, a valid service_id should be allowed to be updated"; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_client_to_sec_client_mapping.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_client_to_sec_client_mapping.cpp new file mode 100644 index 00000000000..17e4addd719 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_client_to_sec_client_mapping.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <memory> +#include <gtest/gtest.h> +#include <common/utility.hpp> + +namespace +{ +vsomeip_v3::client_t client = 10; +vsomeip_v3::uid_t uid = 4003030; +vsomeip_v3::gid_t gid = 4003032; +vsomeip_sec_ip_addr_t host_address = 0; +} + +TEST(remove_client_to_sec_client_mapping, check_no_policies_loaded) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + vsomeip_sec_client_t its_sec_client = utility::create_uds_client(uid, gid, host_address); + + // client and uid_gid should not be stored yet + EXPECT_FALSE(security->get_client_to_sec_client_mapping (client, its_sec_client)); + + // client and uid_gid should not be stored yet + EXPECT_FALSE(security->remove_client_to_sec_client_mapping(client)); + + // add client and uid_gid mappings + security->store_client_to_sec_client_mapping(client, &its_sec_client); + security->store_sec_client_to_client_mapping(&its_sec_client, client); + + // client and uid_gid mapping should be returned + EXPECT_TRUE(security->get_client_to_sec_client_mapping(client, its_sec_client)); + + // client and uid_gid mapping should be in the vector and able to be removed + EXPECT_TRUE(security->remove_client_to_sec_client_mapping(client)); + + // client and uid_gid should be removed from the vector + EXPECT_FALSE(security->get_client_to_sec_client_mapping(client, its_sec_client)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_security_policy.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_security_policy.cpp new file mode 100644 index 00000000000..e334978e0e8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/security_tests/ut_remove_security_policy.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include <common/utility.hpp> + +namespace { +vsomeip_v3::uid_t invalid_uid = 1; +vsomeip_v3::uid_t valid_uid = 4002200; +vsomeip_v3::gid_t invalid_gid = 1; +vsomeip_v3::gid_t valid_gid = 4003014; +} + +TEST(remove_security_policy_test, check_no_policies_loaded) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // no policies loaded -> remove_security_policy will return true independent of the uid or gid + EXPECT_FALSE(security->remove_security_policy(valid_uid, valid_gid)); + EXPECT_FALSE(security->remove_security_policy(invalid_uid, valid_gid)); + EXPECT_FALSE(security->remove_security_policy(valid_uid, invalid_gid)); + EXPECT_FALSE(security->remove_security_policy(invalid_uid, invalid_gid)); +} + +TEST(remove_security_policy_test, check_policies_loaded) +{ + std::unique_ptr<vsomeip_v3::policy_manager_impl> security(new vsomeip_v3::policy_manager_impl); + + // force load of some policies + std::set<std::string> its_failed; + std::vector<vsomeip_v3::configuration_element> policy_elements; + std::vector<std::string> dir_skip; + utility::read_data(utility::get_all_files_in_dir(utility::get_policies_path(), dir_skip), + policy_elements, its_failed); + + for (const auto &e : policy_elements) + security->load(e, false); + + // check if the load worked + ASSERT_TRUE(policy_elements.size() > 0); + ASSERT_TRUE(its_failed.size() == 0); + + // the check_credentials_ and the policy_enabled_ variables should be set to true + ASSERT_FALSE(security->is_audit()); + ASSERT_TRUE(security->is_enabled()); + + // invalid uid and gid -> remove_security_policy must return false + EXPECT_FALSE(security->remove_security_policy(invalid_uid, invalid_gid)); + + // invalid uid and valid gid -> remove_security_policy must return false + EXPECT_FALSE(security->remove_security_policy(invalid_uid, valid_gid)); + + // valid uid and invalid gid -> remove_security_policy must return false + EXPECT_FALSE(security->remove_security_policy(valid_uid, invalid_gid)); + + // valid uid and gid -> remove_security_policy must return true + EXPECT_TRUE(security->remove_security_policy(valid_uid, valid_gid)); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_tests/ut_ByteOperation.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_tests/ut_ByteOperation.cpp new file mode 100644 index 00000000000..5eee0d70760 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_tests/ut_ByteOperation.cpp @@ -0,0 +1,170 @@ +// Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <gtest/gtest.h> + +#include "../../../implementation/utility/include/bithelper.hpp" + +#include <vsomeip/defines.hpp> + +TEST(byte_operations, MACRO_VSOMEIP_BYTES_TO_WORD) +{ + uint8_t payload[8] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + + uint16_t its_service = vsomeip_v3::bithelper::read_uint16_be(payload+VSOMEIP_SERVICE_POS_MIN); + uint16_t its_method = vsomeip_v3::bithelper::read_uint16_be(payload+VSOMEIP_METHOD_POS_MIN); + + EXPECT_EQ(its_service, 0x1112); + EXPECT_EQ(its_method, 0x1314); +} + +TEST(byte_operations, MACRO_VSOMEIP_BYTES_TO_LONG) +{ + uint8_t payload[8] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + + uint32_t its_data = vsomeip_v3::bithelper::read_uint32_be(payload+2); + EXPECT_EQ(its_data, 0x13141516); + + uint32_t its_data2 = vsomeip_v3::bithelper::read_uint32_le(payload+2); + EXPECT_EQ(its_data2, 0x16151413); +} + +TEST(byte_operations, MACRO_VSOMEIP_BYTES_TO_LONG_LONG) +{ + uint8_t payload[8] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + + uint64_t its_data = vsomeip_v3::bithelper::read_uint64_be(payload); + EXPECT_EQ(its_data, 0x1112131415161718); +} + +TEST(byte_operations, MACRO_VSOMEIP_WORDS_TO_LONG) { + uint16_t serviceid = 0x1111; + uint16_t methodid = 0x2222; + + const uint8_t request_message[] = {static_cast<uint8_t>((serviceid & 0xFF00) >> 8), + static_cast<uint8_t>( serviceid & 0x00FF), + static_cast<uint8_t>((methodid & 0xFF00) >> 8), + static_cast<uint8_t>( methodid & 0x00FF)}; + uint32_t header_method = vsomeip_v3::bithelper::read_uint32_be(request_message); + + EXPECT_EQ(header_method, 0x11112222); +} + +TEST(byte_operations, MACRO_VSOMEIP_WORD_BYTEx) { + uint16_t clientid = 0x1234; + uint8_t client[sizeof(clientid)] = {0}; + + vsomeip_v3::bithelper::write_uint16_be(clientid, client); + EXPECT_EQ(client[0], 0x12); + EXPECT_EQ(client[1], 0x34); + + vsomeip_v3::bithelper::write_uint16_le(clientid, client); + EXPECT_EQ(client[0], 0x34); + EXPECT_EQ(client[1], 0x12); +} + +TEST(byte_operations, MACRO_VSOMEIP_LONG_BYTEx) { + uint32_t payload = 0x12345678; + uint8_t data[sizeof(payload)] = {0}; + + vsomeip_v3::bithelper::write_uint32_be(payload, data); + EXPECT_EQ(data[0], 0x12); + EXPECT_EQ(data[1], 0x34); + EXPECT_EQ(data[2], 0x56); + EXPECT_EQ(data[3], 0x78); + + vsomeip_v3::bithelper::write_uint32_le(payload, data); + EXPECT_EQ(data[0], 0x78); + EXPECT_EQ(data[1], 0x56); + EXPECT_EQ(data[2], 0x34); + EXPECT_EQ(data[3], 0x12); +} + +TEST(byte_operations, MACRO_VSOMEIP_LONG_LONG_BYTEx) { + uint64_t payload = 0x1214161821232527; + uint8_t data[sizeof(payload)] = {0}; + + vsomeip_v3::bithelper::write_uint64_be(payload, data); + EXPECT_EQ(data[0], 0x12); + EXPECT_EQ(data[1], 0x14); + EXPECT_EQ(data[2], 0x16); + EXPECT_EQ(data[3], 0x18); + EXPECT_EQ(data[4], 0x21); + EXPECT_EQ(data[5], 0x23); + EXPECT_EQ(data[6], 0x25); + EXPECT_EQ(data[7], 0x27); + + vsomeip_v3::bithelper::write_uint64_le(payload, data); + EXPECT_EQ(data[0], 0x27); + EXPECT_EQ(data[1], 0x25); + EXPECT_EQ(data[2], 0x23); + EXPECT_EQ(data[3], 0x21); + EXPECT_EQ(data[4], 0x18); + EXPECT_EQ(data[5], 0x16); + EXPECT_EQ(data[6], 0x14); + EXPECT_EQ(data[7], 0x12); + +} + +TEST(byte_operations, MACRO_VSOMEIP_LONG_WORDx) { + uint32_t payload = 0x12345678; + uint8_t data[sizeof(payload)] = {0}; + + vsomeip_v3::bithelper::write_uint32_le(payload, data); + EXPECT_EQ(data[0], 0x78); + EXPECT_EQ(data[1], 0x56); + EXPECT_EQ(data[2], 0x34); + EXPECT_EQ(data[3], 0x12); +} + +TEST(byte_operations, TestUint16) { + uint8_t input[] = {0xab, 0xcd}; + EXPECT_EQ(0xabcd, vsomeip_v3::bithelper::read_uint16_be(input)); + + uint8_t output[sizeof(input)] = {0}; + vsomeip_v3::bithelper::write_uint16_be(0x1234, output); + EXPECT_EQ(0x12, output[0]); + EXPECT_EQ(0x34, output[1]); +} + +TEST(byte_operations, TestUint32_BigEndian) { + uint8_t input[] = {0x12, 0x34, 0x56, 0x78}; + EXPECT_EQ(0x12345678U, vsomeip_v3::bithelper::read_uint32_be(input)); + + uint8_t output[sizeof(uint32_t)] = {0}; + vsomeip_v3::bithelper::write_uint32_be(0xabcd1234, output); + EXPECT_EQ(0xab, output[0]); + EXPECT_EQ(0xcd, output[1]); + EXPECT_EQ(0x12, output[2]); + EXPECT_EQ(0x34, output[3]); +} + +TEST(byte_operations, TestUint32_LittleEndian) { + uint8_t input[] = {0x12, 0x34, 0x56, 0x78}; + EXPECT_EQ(0x78563412U, vsomeip_v3::bithelper::read_uint32_le(input)); + + uint8_t output[sizeof(uint32_t)] = {0}; + vsomeip_v3::bithelper::write_uint32_le(0xabcd1234, output); + EXPECT_EQ(0xab, output[3]); + EXPECT_EQ(0xcd, output[2]); + EXPECT_EQ(0x12, output[1]); + EXPECT_EQ(0x34, output[0]); +} + +TEST(byte_operations, TestUint64) { + uint8_t input[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}; + EXPECT_EQ(0x1234567890ABCDEFULL, vsomeip_v3::bithelper::read_uint64_be(input)); + + uint8_t output[sizeof(input)] = {0}; + vsomeip_v3::bithelper::write_uint64_be(0x1234567890ABCDEFULL, output); + EXPECT_EQ(0x12, output[0]); + EXPECT_EQ(0x34, output[1]); + EXPECT_EQ(0x56, output[2]); + EXPECT_EQ(0x78, output[3]); + EXPECT_EQ(0x90, output[4]); + EXPECT_EQ(0xab, output[5]); + EXPECT_EQ(0xcd, output[6]); + EXPECT_EQ(0xef, output[7]); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/CMakeLists.txt new file mode 100644 index 00000000000..9f37c2a892d --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2015-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +project("unit_tests_utility_tests" LANGUAGES CXX) + +file(GLOB SRCS ../main.cpp *.cpp) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# ---------------------------------------------------------------------------- +# Executable and libraries to link +# ---------------------------------------------------------------------------- +add_executable(${PROJECT_NAME} ${SRCS}) +target_link_libraries( + ${PROJECT_NAME} + vsomeip3 + vsomeip3-cfg + ${Boost_LIBRARIES} + ${DL_LIBRARY} + gtest + vsomeip_utilities +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +add_dependencies(build_unit_tests ${PROJECT_NAME}) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/ut_utility.cpp b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/ut_utility.cpp new file mode 100644 index 00000000000..cf0109dadd1 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/test/unit_tests/utility_utility_tests/ut_utility.cpp @@ -0,0 +1,451 @@ +// Copyright (C) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include <gtest/gtest.h> +#include <vsomeip/defines.hpp> + +#include "../../../implementation/configuration/include/configuration_impl.hpp" +#include "../../../implementation/utility/include/bithelper.hpp" +#include "../../../implementation/utility/include/utility.hpp" + +using vsomeip_v3::bithelper; + +namespace { + const std::uint8_t array_size = 18; + const std::uint8_t array_size_too_short = 2; + const std::uint32_t payload_length = 2; + const vsomeip_v3::byte_t serviceID_byte1 = 0x01; + const vsomeip_v3::byte_t serviceID_byte2 = 0x02; + const vsomeip_v3::byte_t methodID_byte1 = 0x03; + const vsomeip_v3::byte_t methodID_byte2 = 0x04; + const vsomeip_v3::byte_t length_byte1 = 0x00; + const vsomeip_v3::byte_t length_byte2 = 0x00; + const vsomeip_v3::byte_t length_byte3 = 0x00; + const vsomeip_v3::byte_t length_byte4 = 0x0A; + const vsomeip_v3::byte_t clientID_byte1 = 0x00; + const vsomeip_v3::byte_t clientID_byte2 = 0x00; + const vsomeip_v3::byte_t sessionID_byte1 = 0x00; + const vsomeip_v3::byte_t sessionID_byte2 = 0x00; + const vsomeip_v3::byte_t version_byte = 0x01; + const vsomeip_v3::byte_t interface_byte = 0x02; + const vsomeip_v3::byte_t messageType_byte = 0x02; + const vsomeip_v3::byte_t returnCode_byte = 0x00; + const vsomeip_v3::byte_t payload_byte1 = 0x13; + const vsomeip_v3::byte_t payload_byte2 = 0x37; +} + +TEST(utility_test, get_message_size) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Create an array of size 18. 4 header, 4 size, 10 payload bytes. + std::array<vsomeip_v3::byte_t, array_size> byte_array_{ + serviceID_byte1, serviceID_byte2, + methodID_byte1, methodID_byte2, + length_byte1, length_byte2, length_byte3, length_byte4, + clientID_byte1, clientID_byte2, + sessionID_byte1, sessionID_byte2, + version_byte, + interface_byte, + messageType_byte, + returnCode_byte, + payload_byte1, payload_byte2 + }; + + // Create an array to pass to bithelper. + std::array<vsomeip_v3::byte_t, 4> uint32_array_{length_byte1, length_byte2, length_byte3, length_byte4}; + + // Getting size. + std::uint32_t size_ = VSOMEIP_SOMEIP_HEADER_SIZE + bithelper::read_uint32_be(uint32_array_.data()); + + // Check if function returns the uint32_t size_ we expect to receive, header + size passed by the 4 length_bytes. + ASSERT_EQ(its_utility->get_message_size(byte_array_.data(), byte_array_.size()), size_); + + // Make the 4 size bytes equal to zero. + byte_array_.at(4) = 0; + byte_array_.at(5) = 0; + byte_array_.at(6) = 0; + byte_array_.at(7) = 0; + // Check that the message size is now equal to only the someip header. + ASSERT_EQ(its_utility->get_message_size(byte_array_.data(), byte_array_.size()), VSOMEIP_SOMEIP_HEADER_SIZE); + + // Create an array shorter than the minimum someip header. + std::array<vsomeip_v3::byte_t, array_size_too_short> byte_array_too_short{serviceID_byte1, serviceID_byte2}; + // Check that 0 is returned for the expected length of the message. + ASSERT_EQ(its_utility->get_message_size(byte_array_too_short.data(), byte_array_too_short.size()), 0); +} + +TEST(utility_test, get_payload_size) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Anatomy of a SOMEIP message. + // Byte 1-2: Service ID, Byte 3-4: Method ID, Byte 5-8: length, + // byte 9-10: Client id, byte 11-12: session id, + // byte 13: SOME/IP version, byte 14: interface version, + // byte 15: Message type, byte 16: Return Code. + // Length are all the bytes that come after it. (byte 9+) + // Payload here is the bytes that come after all those (byte 16++). + + // Create an array of size 18. 4 header, 4 size, 10 payload bytes. + std::array<vsomeip_v3::byte_t, array_size> byte_array_{ + serviceID_byte1, serviceID_byte2, + methodID_byte1, methodID_byte2, + length_byte1, length_byte2, length_byte3, length_byte4, + clientID_byte1, clientID_byte2, + sessionID_byte1, sessionID_byte2, + version_byte, + interface_byte, + messageType_byte, + returnCode_byte, + payload_byte1, payload_byte2 + }; + + // Check if function returns the uint32_t size_ we expect to receive, header + size passed by the 4 length_bytes. + ASSERT_EQ(its_utility->get_payload_size(byte_array_.data(), byte_array_.size()), payload_length); + + // Check if function returns 0, if length field we pass (0x0A) passed is greater than the array size - 8 + ASSERT_EQ(its_utility->get_payload_size(byte_array_.data(), byte_array_.size() - VSOMEIP_SOMEIP_HEADER_SIZE), 0); + + // Make the length smaller than 8. + byte_array_.at(4) = 0; + byte_array_.at(5) = 0; + byte_array_.at(6) = 0; + byte_array_.at(7) = 7; + // Check that the message size is now equal to only the someip header. + ASSERT_EQ(its_utility->get_payload_size(byte_array_.data(), byte_array_.size()), 0); + + // Create an array shorter than the minimum someip header. + std::array<vsomeip_v3::byte_t, array_size_too_short> byte_array_too_short{serviceID_byte1, serviceID_byte2}; + // Check that 0 is returned for the expected length of the message. + ASSERT_EQ(its_utility->get_payload_size(byte_array_too_short.data(), byte_array_too_short.size()), 0); +} + +TEST(utility_test, is_routing_manager) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("test_network"); + + // First caller become the routing manager. + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Subsequent callers can not be routing manager. + ASSERT_FALSE(its_utility->is_routing_manager(network_)); + + // Clean up. + its_utility->remove_lockfile(network_); + + std::unique_ptr<vsomeip_v3::utility> its_utility2; + + // Weird network name. + const std::string network2_("\\\\////\0"); + + // Expect the network name to lead to failure. + ASSERT_FALSE(its_utility2->is_routing_manager(network2_)); +} + +TEST(utility_test, remove_lockfile) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("test"); + + // Expect nothing to happen. + its_utility->remove_lockfile(network_); + + // First caller become the routing manager. + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Subsequent callers can not be routing manager. + ASSERT_FALSE(its_utility->is_routing_manager(network_)); + + its_utility->remove_lockfile(network_); + + // Since the network got erased this shoud return true once more, as new "first caller". + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Clean up. + its_utility->remove_lockfile(network_); + + // WIP not sure how to rest failure to close or remove the test.lck file. +} + +TEST(utility_test, exists) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("exists_tests"); + + // Expect false. + ASSERT_FALSE(its_utility->exists(network_)); + + // First caller become the routing manager, creating the network creates file /tmp/exists_tests.lck + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Create a path variable. + const std::string path_("/tmp/exists_tests.lck"); + + // Expect true. + ASSERT_TRUE(its_utility->exists(path_)); + + // Clean up. + its_utility->remove_lockfile(network_); + + // Expect false since file should be erased. + ASSERT_FALSE(its_utility->exists(path_)); +} + +TEST(utility_test, is_file) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("is_file_tests"); + const std::string file_("/tmp/is_file_tests.lck"); + const std::string directory_("/tmp/"); + + // Expect false. + ASSERT_FALSE(its_utility->is_file(network_)); + + // Expect false since file is not yet created. + ASSERT_FALSE(its_utility->is_file(file_)); + + // Expect false since we pass a directory. + ASSERT_FALSE(its_utility->is_file(directory_)); + + // First caller become the routing manager, creating the network creates file /tmp/is_file_tests.lck + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Expect true. + ASSERT_TRUE(its_utility->is_file(file_)); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, is_folder) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("is_folder_tests"); + const std::string file_("/tmp/is_folder_tests.lck"); + const std::string directory_("/tmp/"); + + // Expect false. + ASSERT_FALSE(its_utility->is_folder(network_)); + + // Expect false since file is not a folder. + ASSERT_FALSE(its_utility->is_folder(file_)); + + // First caller become the routing manager, creating the network creates file /tmp/is_folder_tests.lck + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Expect true. + ASSERT_TRUE(its_utility->is_folder(directory_)); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, get_base_path) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + // Random network name. + const std::string network_("is_folder_tests"); + const std::string base_path_("/tmp/is_folder_tests-"); + + // First caller become the routing manager, creating the network creates file /tmp/is_folder_tests.lck + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Assert equal + ASSERT_EQ(its_utility->get_base_path(network_), base_path_); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, request_client_id) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + const std::string path_("/tmp/"); + std::shared_ptr<vsomeip_v3::cfg::configuration_impl> its_config = + std::make_shared<vsomeip_v3::cfg::configuration_impl>(path_); + + // Client info + vsomeip_v3::client_t client_ = 0x1000; + const std::string client_name_("client"); + vsomeip_v3::client_t client2_ = VSOMEIP_CLIENT_UNSET; + const std::string client_name2_("client2"); + + // Default network name of config + const std::string network_("vsomeip"); + + // Network should not exist yet, expect client to be unset. + ASSERT_EQ(its_utility->request_client_id(its_config, client_name_, client_), VSOMEIP_CLIENT_UNSET); + + // Call is_routing_manager to create the network + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Test method expect to return the client_ id. + ASSERT_EQ(its_utility->request_client_id(its_config, client_name_, client_), client_); + + // Get from the configs the smallest and biggest client numbers that can be assigned. + // Should be 0x100 to 0x1ff + static const std::uint16_t its_diagnosis_mask = its_config->get_diagnosis_mask(); + static const std::uint16_t its_masked_diagnosis_address = static_cast<std::uint16_t>( + (its_config->get_diagnosis_address() << 8) & its_diagnosis_mask); + static const std::uint16_t its_client_mask = static_cast<std::uint16_t>(~its_diagnosis_mask); + static const std::uint16_t its_biggest_client = its_masked_diagnosis_address | its_client_mask; + static const std::uint16_t its_smallest_client = its_masked_diagnosis_address; + + std::uint16_t client_id = its_utility->request_client_id(its_config, client_name2_, client2_); + + // Expect first call with unset id to be the smallest client allowed +1. + ASSERT_EQ(client_id, its_smallest_client+1); + + // Cycle through all numbers available. + while(client_id < its_biggest_client) + { + client_id = its_utility->request_client_id(its_config, client_name2_, client2_); + ASSERT_GE(client_id, its_smallest_client); + ASSERT_LE(client_id, its_biggest_client); + } + + // Expect the client id to be the biggest client client number allowed. + ASSERT_EQ(client_id, its_biggest_client); + + // Expect unset since all numbers have been used. + ASSERT_EQ(its_utility->request_client_id(its_config, client_name2_, client2_), VSOMEIP_CLIENT_UNSET); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, get_used_client_ids) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + const std::string path_("/tmp/"); + std::shared_ptr<vsomeip_v3::cfg::configuration_impl> its_config = + std::make_shared<vsomeip_v3::cfg::configuration_impl>(path_); + + // Client info + vsomeip_v3::client_t client_ = 0x1000; + vsomeip_v3::client_t client1_ = 0x1001; + vsomeip_v3::client_t client2_ = 0x1002; + vsomeip_v3::client_t client3_ = 0x1003; + vsomeip_v3::client_t client4_ = 0x1004; + const std::string client_name_("client"); + + // Default network name of config + const std::string network_("vsomeip"); + + // Call is_routing_manager to create the network + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Call request client id to emplace a client. + ASSERT_EQ(its_utility->request_client_id(its_config, client_name_, client_), client_); + + // Test method expect to return the client_ id. + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 1); + + its_utility->request_client_id(its_config, client_name_, client1_); + its_utility->request_client_id(its_config, client_name_, client2_); + its_utility->request_client_id(its_config, client_name_, client3_); + its_utility->request_client_id(its_config, client_name_, client4_); + + // Test method expect to return the client_ id. + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 5); + ASSERT_EQ(its_utility->get_used_client_ids(network_).count(VSOMEIP_CLIENT_UNSET), 0); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, release_client_id) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + const std::string path_("/tmp/"); + std::shared_ptr<vsomeip_v3::cfg::configuration_impl> its_config = + std::make_shared<vsomeip_v3::cfg::configuration_impl>(path_); + + // Client info + vsomeip_v3::client_t client_ = 0x1000; + vsomeip_v3::client_t client1_ = 0x1001; + vsomeip_v3::client_t client2_ = 0x1002; + vsomeip_v3::client_t client3_ = 0x1003; + vsomeip_v3::client_t client4_ = 0x1004; + const std::string client_name_("client"); + + // Default network name of config + const std::string network_("vsomeip"); + + // Call is_routing_manager to create the network + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Call request client id to emplace a clients. + its_utility->request_client_id(its_config, client_name_, client_); + its_utility->request_client_id(its_config, client_name_, client1_); + its_utility->request_client_id(its_config, client_name_, client2_); + its_utility->request_client_id(its_config, client_name_, client3_); + its_utility->request_client_id(its_config, client_name_, client4_); + + // Expect to get size 5 + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 5); + + // Test Method. + its_utility->release_client_id(network_, client_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 4); + + its_utility->release_client_id(network_, client1_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 3); + + its_utility->release_client_id(network_, client2_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 2); + + its_utility->release_client_id(network_, client3_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 1); + + its_utility->release_client_id(network_, client4_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 0); + + // Clean up + its_utility->remove_lockfile(network_); +} + +TEST(utility_test, reset_client_ids) { + std::unique_ptr<vsomeip_v3::utility> its_utility; + + const std::string path_("/tmp/"); + std::shared_ptr<vsomeip_v3::cfg::configuration_impl> its_config = + std::make_shared<vsomeip_v3::cfg::configuration_impl>(path_); + + // Client info + vsomeip_v3::client_t client_ = 0x1000; + vsomeip_v3::client_t client1_ = 0x1001; + vsomeip_v3::client_t client2_ = 0x1002; + vsomeip_v3::client_t client3_ = 0x1003; + vsomeip_v3::client_t client4_ = 0x1004; + const std::string client_name_("client"); + + // Default network name of config + const std::string network_("vsomeip"); + + // Call is_routing_manager to create the network + ASSERT_TRUE(its_utility->is_routing_manager(network_)); + + // Call request client id to emplace a clients. + its_utility->request_client_id(its_config, client_name_, client_); + its_utility->request_client_id(its_config, client_name_, client1_); + its_utility->request_client_id(its_config, client_name_, client2_); + its_utility->request_client_id(its_config, client_name_, client3_); + its_utility->request_client_id(its_config, client_name_, client4_); + + // Expect to get size 5 + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 5); + + // Test Method. + its_utility->reset_client_ids(network_); + ASSERT_EQ(its_utility->get_used_client_ids(network_).size(), 0); + + // Clean up + its_utility->remove_lockfile(network_); +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/CMakeLists.txt b/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/CMakeLists.txt new file mode 100644 index 00000000000..8756f3f241a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# vsomeip_ctrl +add_executable(vsomeip_ctrl EXCLUDE_FROM_ALL vsomeip_ctrl.cpp) +target_link_libraries(vsomeip_ctrl + vsomeip3 + ${Boost_LIBRARIES} + ${DL_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} +) + +################################################################################################### + diff --git a/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/vsomeip_ctrl.cpp b/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/vsomeip_ctrl.cpp new file mode 100644 index 00000000000..9051fdc2cd8 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/tools/vsomeip_ctrl/vsomeip_ctrl.cpp @@ -0,0 +1,437 @@ +// Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <vsomeip/vsomeip.hpp> +#include <vsomeip/internal/logger.hpp> + +#include "../implementation/service_discovery/include/constants.hpp" +#include "../implementation/utility/include/bithelper.hpp" + +#include <cstdint> +#include <thread> +#include <cstring> +#include <condition_variable> +#include <iomanip> +#include <iostream> +#include <sstream> + +namespace vsomeip_ctrl { + +class vsomeip_sender { +public: + vsomeip_sender(bool _use_tcp, + const std::vector<vsomeip::byte_t>& _user_message, + vsomeip::instance_t _instance) : + use_tcp_(_use_tcp), + user_message_(_user_message), + instance_(_instance), + app_(vsomeip::runtime::get()->create_application("vsomeip_ctrl")), + wait_service_available_(true), + service_id_(0x0), + method_id_(0x0), + length_(0), + client_id_(0x0), + interface_version_(0x0), + message_type_(vsomeip::message_type_e::MT_UNKNOWN), + return_code_(vsomeip::return_code_e::E_UNKNOWN), + wait_for_answer_(true) + { + send_thread_ = std::thread{&vsomeip_sender::send, this}; + + if (user_message_.size() < VSOMEIP_PAYLOAD_POS) { + VSOMEIP_ERROR << "Provided message is to short, min. length " + "is 16 Bytes, exiting."; + exit(EXIT_FAILURE); + } + + service_id_ = vsomeip::bithelper::read_uint16_be(&user_message_[VSOMEIP_SERVICE_POS_MIN]); + method_id_ = vsomeip::bithelper::read_uint16_be(&user_message_[VSOMEIP_METHOD_POS_MIN]); + length_ = vsomeip::bithelper::read_uint32_be(&user_message_[VSOMEIP_LENGTH_POS_MIN]); + client_id_ = vsomeip::bithelper::read_uint16_be(&user_message_[VSOMEIP_CLIENT_POS_MIN]); + + interface_version_ = user_message_[VSOMEIP_INTERFACE_VERSION_POS]; + message_type_ = static_cast<vsomeip::message_type_e>(user_message_[VSOMEIP_MESSAGE_TYPE_POS]); + return_code_ = static_cast<vsomeip::return_code_e>(user_message_[VSOMEIP_RETURN_CODE_POS]); + + validate_message(); + + if (!app_->init()) { + VSOMEIP_ERROR << "Couldn't initialize application"; + exit(EXIT_FAILURE); + } + app_->register_state_handler( + std::bind(&vsomeip_sender::on_state, this, + std::placeholders::_1)); + app_->register_message_handler(vsomeip::ANY_SERVICE, + vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, + std::bind(&vsomeip_sender::on_message, this, + std::placeholders::_1)); + app_->register_availability_handler(service_id_, instance_, + std::bind(&vsomeip_sender::on_availability, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + app_->start(); + }; + + void stop(int _exit_code) { + app_->clear_all_handler(); + app_->release_service(service_id_, instance_); + app_->stop(); + exit(_exit_code); + } + + ~vsomeip_sender() { + send_thread_.join(); + } + + void on_state(vsomeip::state_type_e _state) { + VSOMEIP_INFO << "Application " << app_->get_name() << " is " + << (_state == vsomeip::state_type_e::ST_REGISTERED ? + "registered." : "deregistered."); + + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(service_id_, instance_); + } + } + + void on_availability(vsomeip::service_t _service, + vsomeip::instance_t _instance, bool _is_available) { + if(_is_available) { + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') + << std::hex << _service << "." << _instance << "] is available."; + std::lock_guard<std::mutex> its_lock(mutex_); + wait_service_available_ = false; + condition_.notify_one(); + } + } + + void on_message(const std::shared_ptr<vsomeip::message> &_response) { + VSOMEIP_INFO << "Received a response from Service [" + << std::setfill('0') << std::hex + << std::setw(4) << _response->get_service() << "." + << std::setw(4) << _response->get_instance() << "]:"; + VSOMEIP_INFO << "########## begin message"; + VSOMEIP_INFO << std::hex << std::setw(4) << std::setfill('0') + << _response->get_service() + << std::hex << std::setw(4) << std::setfill('0') + << _response->get_method() + << " # service id / instance id"; + VSOMEIP_INFO << std::hex << std::setw(8) << std::setfill('0') + << _response->get_length() << " # length"; + VSOMEIP_INFO << std::hex << std::setw(4) << std::setfill('0') + << _response->get_client() + << std::hex << std::setw(4) << std::setfill('0') + << _response->get_session() + << " # client id / session id"; + VSOMEIP_INFO << std::hex << std::setw(2) << std::setfill('0') + << static_cast<std::uint16_t>(_response->get_protocol_version()) + << std::hex << std::setw(2) << std::setfill('0') + << static_cast<std::uint16_t>(_response->get_interface_version()) + << std::hex << std::setw(2) << std::setfill('0') + << static_cast<std::uint16_t>(_response->get_message_type()) + << std::hex << std::setw(2) << std::setfill('0') + << static_cast<std::uint16_t>(_response->get_return_code()) + << " # protocol version / interface version / " + << "message type / return code"; + + + std::stringstream stream; + std::string str; + for(unsigned int i = 0; i < _response->get_payload()->get_length(); i++) { + stream << std::hex << std::setw(2) << std::setfill('0') + << static_cast<std::uint32_t>((_response->get_payload()->get_data())[i]); + str.append(stream.str()); + stream.str(""); + stream.clear(); + } + std::string str2; + int k=1; + for(unsigned int j = 0; j < str.length(); j+=2, k++) { + str2.append(str.substr(j,2)); + if(k%4 == 0) { + if(k == 4) { + VSOMEIP_INFO << str2 << " # payload from here on"; + } else { + VSOMEIP_INFO << str2; + } + str2.clear(); + } + } + VSOMEIP_INFO << "########## end message"; + VSOMEIP_INFO << "Payload as byte stream: " << str; + str.clear(); + std::lock_guard<std::mutex> its_lock(mutex_); + wait_for_answer_ = false; + condition_.notify_one(); + } + + void send() { + std::unique_lock<std::mutex> its_lock(mutex_); + while (wait_service_available_) { + if(std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(6))) { + VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0') + << std::hex << service_id_ << "." << instance_ << "] isn't available. Exiting"; + stop(EXIT_FAILURE); + } + } + + std::shared_ptr<vsomeip::message> its_message = + vsomeip::runtime::get()->create_message(use_tcp_); + its_message->set_method(method_id_); + its_message->set_service(service_id_); + its_message->set_interface_version(interface_version_); + its_message->set_message_type(message_type_); + its_message->set_return_code(return_code_); + its_message->set_client(app_->get_client()); + its_message->set_instance(instance_); + + std::shared_ptr< vsomeip::payload > its_payload = + vsomeip::runtime::get()->create_payload(); + its_payload->set_data(&user_message_[VSOMEIP_PAYLOAD_POS], + static_cast<vsomeip::length_t>(user_message_.size() - VSOMEIP_PAYLOAD_POS)); + its_message->set_payload(its_payload); + VSOMEIP_INFO << "Sending"; + app_->send(its_message); + + while(wait_for_answer_) { + if(std::cv_status::timeout == condition_.wait_for(its_lock, std::chrono::seconds(5))) { + VSOMEIP_INFO << "Didn't receive answer within 5sec. Shutting down."; + stop(EXIT_SUCCESS); + break; + } + } + + stop(EXIT_SUCCESS); + } + +private: + bool validate_message() { + if (!check_message_type()) { + VSOMEIP_ERROR << "Invalid message type 0x" << std::setw(2) + << std::setfill('0') << std::hex + << static_cast<std::uint8_t>(message_type_) << ", exiting."; + stop(EXIT_FAILURE); + } + + if(!check_return_code()) { + VSOMEIP_ERROR << "Invalid return code 0x" << std::setw(2) + << std::setfill('0') << std::hex + << static_cast<std::uint8_t>(return_code_) << ", exiting."; + stop(EXIT_FAILURE); + } + + if (service_id_ == vsomeip::sd::service && + method_id_ == vsomeip::sd::method) { + VSOMEIP_ERROR << "Usage of reserved service id and method id " + "of service discovery, exiting."; + stop(EXIT_FAILURE); + } + + if (user_message_.size() != length_ + 8) { + VSOMEIP_ERROR << "Provided length 0x" << std::setw(8) + << std::setfill('0') << std::hex << length_ + << " doesn't match message size."; + VSOMEIP_ERROR << "Assuming the same payload the length field should" + " be set to 0x" << std::setw(8) << std::setfill('0') + << std::hex << user_message_.size() - 8 << " , exiting."; + stop(EXIT_FAILURE); + } + + if (use_tcp_ && user_message_.size() > VSOMEIP_MAX_TCP_MESSAGE_SIZE) { + VSOMEIP_WARNING << "Max allowed message size for TCP is " + << std::dec << VSOMEIP_MAX_TCP_MESSAGE_SIZE + << ". Provided message size is: " << user_message_.size(); + } + if (!use_tcp_ && user_message_.size() > VSOMEIP_MAX_UDP_MESSAGE_SIZE) { + VSOMEIP_WARNING << "Max allowed message size for UDP is " + << std::dec << VSOMEIP_MAX_UDP_MESSAGE_SIZE + << ". Provided message size is: " << user_message_.size(); + } + return true; + } + + bool check_message_type() { + switch (message_type_) { + case vsomeip::message_type_e::MT_REQUEST: + case vsomeip::message_type_e::MT_REQUEST_NO_RETURN: + case vsomeip::message_type_e::MT_NOTIFICATION: + case vsomeip::message_type_e::MT_RESPONSE: + case vsomeip::message_type_e::MT_ERROR: + return true; + break; + case vsomeip::message_type_e::MT_UNKNOWN: + case vsomeip::message_type_e::MT_ERROR_ACK: + case vsomeip::message_type_e::MT_RESPONSE_ACK: + case vsomeip::message_type_e::MT_NOTIFICATION_ACK: + case vsomeip::message_type_e::MT_REQUEST_NO_RETURN_ACK: + case vsomeip::message_type_e::MT_REQUEST_ACK: + default: + return false; + break; + } + } + + bool check_return_code() { + if (static_cast<std::uint8_t>(return_code_) > 0x3F) { + VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2) + << std::setfill('0') << std::hex + << static_cast<std::uint8_t>(return_code_) << " is out of range."; + return false; + } + if (static_cast<std::uint8_t>(return_code_) > + static_cast<std::uint8_t>(vsomeip::return_code_e::E_WRONG_MESSAGE_TYPE) && + static_cast<std::uint8_t>(return_code_) <= 0x3f) { + VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2) + << std::setfill('0') << std::hex << + static_cast<std::uint8_t>(return_code_) << "is reserved."; + return false; + } + switch (message_type_) { + case vsomeip::message_type_e::MT_REQUEST: + case vsomeip::message_type_e::MT_REQUEST_NO_RETURN: + case vsomeip::message_type_e::MT_NOTIFICATION: + if(return_code_ != vsomeip::return_code_e::E_OK) { + VSOMEIP_ERROR << "Provided return code 0x" << std::setw(2) + << std::setfill('0') << std::hex + << static_cast<std::uint8_t>(return_code_) + << "is invalid in combination with message type 0x" + << std::setw(2) << std::setfill('0') << std::hex + << static_cast<std::uint8_t>(message_type_) + << " use 0x00 (E_OK)."; + return false; + } + return true; + break; + default: + return true; + break; + } + } + +private: + bool use_tcp_; + std::vector<vsomeip::byte_t> user_message_; + vsomeip::instance_t instance_; + std::shared_ptr<vsomeip::application> app_; + std::mutex mutex_; + std::condition_variable condition_; + bool wait_service_available_; + std::thread send_thread_; + vsomeip::service_t service_id_; + vsomeip::method_t method_id_; + std::uint32_t length_; + vsomeip::client_t client_id_; + vsomeip::interface_version_t interface_version_; + vsomeip::message_type_e message_type_; + vsomeip::return_code_e return_code_; + bool wait_for_answer_; +}; +} // namespace vsomeip_ctrl + +static void print_help(char* binary_name) { + std::cout << "Usage example:" << std::endl; + std::cout << binary_name << " --instance 5678 " + << "--message 123480e800000015134300030100000000000009efbbbf576f726c6400\n" + << "This will send a message to service with service id 1234 and instance 5678." + << std::endl << std::endl; + std::cout << + "Available options:\n" + "--help | -h : print this help\n" + "--instance | -i : instance id of target service in hex (required)\n" + "--tcp | -t : flag to enable sending over TCP, default off (= UDP)\n" + "--message | -m : vSomeIP message to send in hex (required)\n\n" + "Please note: the fields client id and session id in the provided message\n" + "will be overwritten by the stack with the required values\n" + "Please further make sure to use the same configuration file\n" + "as the target service, if the system is not using routingmanagerd" << std::endl; +} + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "To few arguments, please see the help with : " + << argv[0] << " --help" << std::endl; + exit(EXIT_FAILURE); + } + + std::vector<vsomeip::byte_t> user_message; + vsomeip::instance_t instance(vsomeip::ANY_INSTANCE); + bool use_tcp(false); + + for (int i = 1; i < argc; i++) { + std::string arg(argv[i]); + if (arg == "--help" || arg == "-h") { + print_help(argv[0]); + exit(EXIT_SUCCESS); + break; + } else if (arg == "--message" || arg == "-m") { + std::string message(argv[i + 1]); + for (unsigned int i = 0; i < message.length(); i += 2) { + vsomeip::byte_t its_byte; + try { + std::uint64_t tmp = std::stoul(message.substr(i, 2), 0, 16); + tmp = (tmp > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : tmp; + its_byte = static_cast<vsomeip::byte_t>(tmp); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << ": Couldn't convert '" + << message.substr(i, 2) << "' to hex, exiting: " + << std::endl; + exit(EXIT_FAILURE); + } + user_message.push_back(its_byte); + } + } if (arg == "--tcp" || arg == "-t") { + use_tcp = true; + } else if (arg == "--instance" || arg == "-i") { + std::string instance_str(argv[i + 1]); + if(instance_str.length() > 4) { + std::cerr << "provided instance is to long, exiting." << std::endl; + exit(EXIT_FAILURE); + } + if(instance_str.length() < 4) { + while(instance_str.size() != 4) { + instance_str = std::string("0") += instance_str; + } + } + vsomeip::byte_t high(0x0); + vsomeip::byte_t low(0x0); + std::cout << "Instance: " << instance_str << std::endl; + for (unsigned int i = 0; i < instance_str.length(); i += 2) { + try { + std::uint64_t tmp = std::stoul(instance_str.substr(i, 2), 0, 16); + tmp = (tmp > (std::numeric_limits<std::uint8_t>::max)()) ? + (std::numeric_limits<std::uint8_t>::max)() : tmp; + + vsomeip::byte_t its_byte = static_cast<vsomeip::byte_t>(tmp); + if (i == 0) { + high = its_byte; + } else { + low = its_byte; + } + } catch (std::invalid_argument &e) { + std::cerr << e.what() << ": Couldn't convert '" + << instance_str.substr(i, 2) << "' to hex, exiting: " + << std::endl; + exit(EXIT_FAILURE); + } + } + uint8_t its_instance[2] = {high, low}; + instance = vsomeip::bithelper::read_uint16_be(its_instance); + } + } + + if(instance == vsomeip::ANY_INSTANCE) { + std::cerr << "Please provide a target instance (see --help)" << std::endl; + exit(EXIT_FAILURE); + } + + if(user_message.empty()) { + std::cerr << "Please provide a message to send (see --help)" << std::endl; + exit(EXIT_FAILURE); + } + + vsomeip_ctrl::vsomeip_sender sender(use_tcp, user_message, instance); + return EXIT_SUCCESS; +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/README.md b/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/README.md new file mode 100644 index 00000000000..f3623de944e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/README.md @@ -0,0 +1,13 @@ +# vsomeip-dissector +Wireshark dissector for vSomeip internal communication via TCP + +## How To Use + +1. Place `vsomeip-dissector.lua` file in `~/.config/wireshark/plugins/vsomeip/vsomeip-dissector.lua` + (create `plugins` directory if it doesn't exist) +2. In wireshark go to `Analyze` > `Reload Lua Plugins` +3. In wireshark go to `Analyze` > `Enable Protocols` and search for `vsomeip` and enable it + +## Referances + +vSomeip Protocol definitions: documentation/vsomeipProtocol.md \ No newline at end of file diff --git a/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/vsomeip-dissector.lua b/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/vsomeip-dissector.lua new file mode 100644 index 00000000000..7c49d32d39a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/tools/wireshark_plugin/vsomeip-dissector.lua @@ -0,0 +1,426 @@ +--[[ + Wireshark Lua vsomeip protocol dissector + vsomeip-dissector.lua V0.0.1 +--]] + +protocol_name = 'vsomeip' + +vsomeip_protocol = Proto(protocol_name, protocol_name:upper() .. ' Protocol') +vsomeip_command = ProtoField.uint8(protocol_name .. '.command' , "Command", base.HEX) +vsomeip_version = ProtoField.uint16(protocol_name .. '.version' , "Version", base.DEC) +vsomeip_client = ProtoField.uint16(protocol_name .. '.client' , "Client", base.HEX) +vsomeip_size = ProtoField.uint32(protocol_name .. '.size' , "Size", base.DEC) + +vsomeip_name = ProtoField.string(protocol_name .. '.name' , "Name") + +vsomeip_instance = ProtoField.uint16(protocol_name .. '.instance' , "Instance", base.HEX) +vsomeip_reliable = ProtoField.uint8(protocol_name .. '.reliable' , "Reliable", base.DEC) +vsomeip_crc = ProtoField.bytes(protocol_name .. '.crc' , "CRC", base_HEX) +vsomeip_dstClient = ProtoField.uint16(protocol_name .. '.dstClient' , "Dst Client", base.HEX) +vsomeip_payload = ProtoField.bytes(protocol_name .. '.payload' , "Payload", base_HEX) + +vsomeip_service = ProtoField.uint16(protocol_name .. '.service' , "Service", base.HEX) +vsomeip_eventgroup = ProtoField.uint16(protocol_name .. '.eventgroup' , "Eventgroup", base.HEX) +vsomeip_subscriber = ProtoField.uint16(protocol_name .. '.subscriber' , "Subscriber", base.HEX) +vsomeip_notifier = ProtoField.uint16(protocol_name .. '.notifier' , "Notifier", base.HEX) +vsomeip_event = ProtoField.uint16(protocol_name .. '.event' , "Event", base.HEX) +vsomeip_id = ProtoField.uint16(protocol_name .. '.id' , "ID", base.HEX) + +vsomeip_provided = ProtoField.uint8(protocol_name .. '.provided' , "Provided", base.DEC) + +vsomeip_major = ProtoField.uint8(protocol_name .. '.major' , "Major", base.HEX) +vsomeip_minor = ProtoField.uint32(protocol_name .. '.minor' , "Minor", base.HEX) + +vsomeip_offer_type = ProtoField.uint8(protocol_name .. '.offer_type' , "OfferType", base.DEC) + +vsomeip_pending_offer_id = ProtoField.uint32(protocol_name .. '.pending_offer_id' , "PendingOfferId", base.HEX) + +vsomeip_update_id = ProtoField.uint32(protocol_name .. '.update_id' , "UpdateId", base.HEX) +vsomeip_uid = ProtoField.uint32(protocol_name .. '.uid' , "UID", base.HEX) +vsomeip_gid = ProtoField.uint32(protocol_name .. '.gid' , "GID", base.HEX) +vsomeip_policy_count = ProtoField.uint32(protocol_name .. '.policy_count' , "PoliciesCount", base.HEX) +vsomeip_policy = ProtoField.bytes(protocol_name .. '.policy' , "Policy", base_HEX) + +-- TODO Parse filter in VSOMEIP_SUBSCRIBE +vsomeip_filter = ProtoField.bytes(protocol_name .. '.filter' , "Filter", base_HEX) + +-- TODO make this a subtree to list all entries in VSOMEIP_ROUTING_INFO +vsomeip_entries = ProtoField.bytes(protocol_name .. '.entries' , "Entries", base_HEX) + +-- TODO make this a subtree to list all offered_services in VSOMEIP_OFFERED_SERVICES_RESPONSE +vsomeip_offered_services = ProtoField.bytes(protocol_name .. '.offered_services' , "OfferedServices", base_HEX) + +-- TODO make this a subtree to list all configurations in VSOMEIP_CONFIG +vsomeip_configurations = ProtoField.bytes(protocol_name .. '.configurations' , "Configurations", base_HEX) + +-- TODO make this a subtree to list all configurations in VSOMEIP_UPDATE_SECURITY_CREDENTIALS +vsomeip_credentials = ProtoField.bytes(protocol_name .. '.credentials' , "Credentials", base_HEX) + +-- TODO make this a subtree to list all configurations in VSOMEIP_DISTRIBUTE_SECURITY_POLICIES +vsomeip_policies = ProtoField.bytes(protocol_name .. '.policies' , "Policies", base_HEX) + +vsomeip_protocol.fields = { + vsomeip_command, vsomeip_version, + vsomeip_client, vsomeip_size, + vsomeip_name, + vsomeip_instance, vsomeip_reliable, vsomeip_crc, vsomeip_dstClient, vsomeip_payload, + vsomeip_service, vsomeip_eventgroup, vsomeip_subscriber, vsomeip_notifier, vsomeip_event, vsomeip_id, + vsomeip_provided, + vsomeip_major, vsomeip_minor, + vsomeip_filter, + vsomeip_entries +} + +function vsomeip_protocol.dissector(buffer, pinfo, tree) + local length = buffer:len() + + if length < 9 then + return + end + local vsip_start = buffer(0, 4):uint() + local vsip_end = buffer(length - 4, 4):uint() + -- Is this a vsomeip packet ? vsip packets start with 0x67376D07 and end with 0x076D3767 + if vsip_start ~= 0x67376D07 or vsip_end ~= 0x076D3767 then + return + end + + pinfo.cols.protocol = "vSomeip" + + -- Command + local command_number = buffer(4, 1) + local command_name = get_command_name(command_number:uint()) + + local subtree = tree:add(vsomeip_protocol, buffer(), "vSomeip (" .. length .. " bytes) " .. command_name) + subtree:add_le(vsomeip_command, command_number):append_text(" (" .. command_name .. ")") + pinfo.cols.info = command_name + + if command_name == "VSOMEIP_APPLICATION_LOST" + or command_name == "VSOMEIP_ID_RESPONSE" + or command_name == "VSOMEIP_ID_REQUEST" + or command_name == "VSOMEIP_UNKOWN" + or length < 11 then + return + end + + -- Version + local command_version = buffer(5, 2) + subtree:add_le(vsomeip_version, command_version) + + local buffer_cursor = 7 + if command_name ~= "VSOMEIP_SUSPEND" then + -- Client + local command_client = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + -- Size + local command_size = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + subtree:add_le(vsomeip_client, command_client) + subtree:add_le(vsomeip_size, command_size) + pinfo.cols.info:append(" (" ..command_client(1,1)..command_client(0,1).. ")") + else + -- Size + local command_size = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + subtree:add_le(vsomeip_size, command_size) + end + + -- More Complex commands here (buffer_cursor starts after size) + if command_name == "VSOMEIP_SEND" or command_name == "VSOMEIP_NOTIFY" or command_name == "VSOMEIP_NOTIFY_ONE" then + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_reliable = buffer(buffer_cursor, 1) + local command_reliable_name = get_reliability(command_reliable:uint()) + buffer_cursor = buffer_cursor + 1 + local command_crc = buffer(buffer_cursor, 1) + buffer_cursor = buffer_cursor + 1 + local command_dstClient = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_payload = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add_le(vsomeip_instance, command_instance) + subtree:add(vsomeip_reliable, command_reliable):append_text(" (" .. command_reliable_name .. ")") + subtree:add(vsomeip_crc, command_crc) + subtree:add_le(vsomeip_dstClient, command_dstClient) + subtree:add(vsomeip_payload, command_payload) + + pinfo.cols.info:append(" --"..command_reliable_name.."--> (" ..command_dstClient(1,1)..command_dstClient(0,1).. ")") + elseif command_name == "VSOMEIP_ASSIGN_CLIENT" then + local command_name = buffer(buffer_cursor, length - buffer_cursor - 4) + subtree:add(vsomeip_name, command_name) + + pinfo.cols.info:append(" "..command_name) + + elseif command_name == "VSOMEIP_ROUTING_INFO" then + local command_entries = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add(vsomeip_entries, command_entries) + + elseif command_name == "VSOMEIP_OFFER_SERVICE" or command_name == "VSOMEIP_STOP_OFFER_SERVICE" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_major = buffer(buffer_cursor, 1) + buffer_cursor = buffer_cursor + 1 + local command_minor = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_major, command_major) + subtree:add_le(vsomeip_minor, command_minor) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) .. "]") + + elseif command_name == "VSOMEIP_SUBSCRIBE" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_eventgroup = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_major = buffer(buffer_cursor, 1) + buffer_cursor = buffer_cursor + 1 + local command_event = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_id = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_eventgroup, command_eventgroup) + subtree:add(vsomeip_major, command_major) + subtree:add_le(vsomeip_event, command_event) + subtree:add_le(vsomeip_id, command_id) + if (length - buffer_cursor - 4) > 0 then + local command_filter = buffer(buffer_cursor, length - buffer_cursor - 4) + subtree:add(vsomeip_filter, command_filter) + end + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) + .. "." .. command_eventgroup(1,1)..command_eventgroup(0,1) .. "." .. command_event(1,1)..command_event(0,1) .. "]") + + elseif command_name == "VSOMEIP_UNSUBSCRIBE" or command_name == "VSOMEIP_EXPIRE" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_eventgroup = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_event = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_id = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_eventgroup, command_eventgroup) + subtree:add_le(vsomeip_event, command_event) + subtree:add_le(vsomeip_id, command_id) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) + .. "." .. command_eventgroup(1,1)..command_eventgroup(0,1) .. "." .. command_event(1,1)..command_event(0,1) .. "]") + + elseif command_name == "VSOMEIP_RELEASE_SERVICE" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) .. "]") + + elseif command_name == "VSOMEIP_SUBSCRIBE_NACK" or command_name == "VSOMEIP_SUBSCRIBE_ACK" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_eventgroup = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_subscriber = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_event = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_id = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_eventgroup, command_eventgroup) + subtree:add_le(vsomeip_subscriber, command_subscriber) + subtree:add_le(vsomeip_event, command_event) + subtree:add_le(vsomeip_id, command_id) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) + .. "." .. command_eventgroup(1,1)..command_eventgroup(0,1) .. "." .. command_event(1,1)..command_event(0,1) + .. "] (" .. command_subscriber(1,1)..command_subscriber(0,1) .. ")") + elseif command_name == "VSOMEIP_REGISTER_EVENT" then + local command_entries = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add(vsomeip_entries, command_entries) + + elseif command_name == "VSOMEIP_UNREGISTER_EVENT" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_notifier = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_provided = buffer(buffer_cursor, 1) + buffer_cursor = buffer_cursor + 1 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_notifier, command_notifier) + subtree:add(vsomeip_provided, command_provided) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) .. "]") + + elseif command_name == "VSOMEIP_OFFERED_SERVICES_REQUEST" then + local command_offer_type = buffer(buffer_cursor, 1) + local command_offer_type_name = get_offer_type(command_offer_type:uint()) + + subtree:add(vsomeip_offer_type, command_offer_type):append_text(" (" .. command_offer_type_name .. ")") + + pinfo.cols.info:append(" (" .. command_offer_type_name .. ")") + elseif command_name == "VSOMEIP_OFFERED_SERVICES_RESPONSE" then + local command_offered_services = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add(vsomeip_offered_services, command_offered_services) + + elseif command_name == "VSOMEIP_UNSUBSCRIBE_ACK" then + local command_service = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_instance = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_eventgroup = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + local command_id = buffer(buffer_cursor, 2) + buffer_cursor = buffer_cursor + 2 + + subtree:add_le(vsomeip_service, command_service) + subtree:add_le(vsomeip_instance, command_instance) + subtree:add_le(vsomeip_eventgroup, command_eventgroup) + subtree:add_le(vsomeip_id, command_id) + + pinfo.cols.info:append(" [" .. command_service(1,1)..command_service(0,1) ..".".. command_instance(1,1)..command_instance(0,1) + .. "." .. command_eventgroup(1,1)..command_eventgroup(0,1) .. "]") + elseif command_name == "VSOMEIP_RESEND_PROVIDED_EVENTS" then + local command_pending_offer_id = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + + subtree:add_le(vsomeip_pending_offer_id, command_pending_offer_id) + + elseif command_name == "VSOMEIP_UPDATE_SECURITY_POLICY" or command_name == "VSOMEIP_UPDATE_SECURITY_POLICY_INT" then + local command_update_id = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + local command_offered_services = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add_le(vsomeip_update_id, command_update_id) + subtree:add(vsomeip_offered_services, command_offered_services) + + elseif command_name == "VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE" or command_name == "VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE" then + local command_update_id = buffer(buffer_cursor, 4) + + subtree:add_le(vsomeip_update_id, command_update_id) + elseif command_name == "VSOMEIP_REMOVE_SECURITY_POLICY" then + local command_update_id = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + local command_uid = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + local command_gid = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + + subtree:add_le(vsomeip_update_id, command_update_id) + subtree:add_le(vsomeip_uid, command_uid) + subtree:add_le(vsomeip_gid, command_gid) + + elseif command_name == "VSOMEIP_UPDATE_SECURITY_CREDENTIALS" then + local command_credentials = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add(vsomeip_credentials, command_credentials) + + elseif command_name == "VSOMEIP_DISTRIBUTE_SECURITY_POLICIES" then + local command_policy_count = buffer(buffer_cursor, 4) + buffer_cursor = buffer_cursor + 4 + local command_policies = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add_le(vsomeip_policy_count, command_policy_count) + subtree:add(vsomeip_policies, command_policies) + elseif command_name == "VSOMEIP_CONFIG" then + local command_configurations = buffer(buffer_cursor, length - buffer_cursor - 4) + + subtree:add(vsomeip_configurations, command_configurations) + end +end + +DissectorTable.get('tcp.port'):add('1-65535', vsomeip_protocol) + +function get_command_name(cmd) + local cmd_name = "VSOMEIP_UNKOWN" + + -- ¯\_(ツ)_/¯ + if cmd == 0x00 then cmd_name = "VSOMEIP_ASSIGN_CLIENT" + elseif cmd == 0x01 then cmd_name = "VSOMEIP_ASSIGN_CLIENT_ACK" + elseif cmd == 0x02 then cmd_name = "VSOMEIP_REGISTER_APPLICATION" + elseif cmd == 0x03 then cmd_name = "VSOMEIP_DEREGISTER_APPLICATION" + elseif cmd == 0x04 then cmd_name = "VSOMEIP_APPLICATION_LOST" + elseif cmd == 0x05 then cmd_name = "VSOMEIP_ROUTING_INFO" + elseif cmd == 0x06 then cmd_name = "VSOMEIP_REGISTERED_ACK" + elseif cmd == 0x07 then cmd_name = "VSOMEIP_PING" + elseif cmd == 0x08 then cmd_name = "VSOMEIP_PONG" + elseif cmd == 0x10 then cmd_name = "VSOMEIP_OFFER_SERVICE" + elseif cmd == 0x11 then cmd_name = "VSOMEIP_STOP_OFFER_SERVICE" + elseif cmd == 0x12 then cmd_name = "VSOMEIP_SUBSCRIBE" + elseif cmd == 0x13 then cmd_name = "VSOMEIP_UNSUBSCRIBE" + elseif cmd == 0x14 then cmd_name = "VSOMEIP_REQUEST_SERVICE" + elseif cmd == 0x15 then cmd_name = "VSOMEIP_RELEASE_SERVICE" + elseif cmd == 0x16 then cmd_name = "VSOMEIP_SUBSCRIBE_NACK" + elseif cmd == 0x17 then cmd_name = "VSOMEIP_SUBSCRIBE_ACK" + elseif cmd == 0x18 then cmd_name = "VSOMEIP_SEND" + elseif cmd == 0x19 then cmd_name = "VSOMEIP_NOTIFY" + elseif cmd == 0x1A then cmd_name = "VSOMEIP_NOTIFY_ONE" + elseif cmd == 0x1B then cmd_name = "VSOMEIP_REGISTER_EVENT" + elseif cmd == 0x1C then cmd_name = "VSOMEIP_UNREGISTER_EVENT" + elseif cmd == 0x1D then cmd_name = "VSOMEIP_ID_RESPONSE" + elseif cmd == 0x1E then cmd_name = "VSOMEIP_ID_REQUEST" + elseif cmd == 0x1F then cmd_name = "VSOMEIP_OFFERED_SERVICES_REQUEST" + elseif cmd == 0x20 then cmd_name = "VSOMEIP_OFFERED_SERVICES_RESPONSE" + elseif cmd == 0x21 then cmd_name = "VSOMEIP_UNSUBSCRIBE_ACK" + elseif cmd == 0x22 then cmd_name = "VSOMEIP_RESEND_PROVIDED_EVENTS" + elseif cmd == 0x23 then cmd_name = "VSOMEIP_UPDATE_SECURITY_POLICY" + elseif cmd == 0x24 then cmd_name = "VSOMEIP_UPDATE_SECURITY_POLICY_RESPONSE" + elseif cmd == 0x25 then cmd_name = "VSOMEIP_REMOVE_SECURITY_POLICY" + elseif cmd == 0x26 then cmd_name = "VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE" + elseif cmd == 0x27 then cmd_name = "VSOMEIP_UPDATE_SECURITY_CREDENTIALS" + elseif cmd == 0x28 then cmd_name = "VSOMEIP_DISTRIBUTE_SECURITY_POLICIES" + elseif cmd == 0x29 then cmd_name = "VSOMEIP_UPDATE_SECURITY_POLICY_INT" + elseif cmd == 0x2A then cmd_name = "VSOMEIP_EXPIRE" + elseif cmd == 0x30 then cmd_name = "VSOMEIP_SUSPEND" + elseif cmd == 0x31 then cmd_name = "VSOMEIP_CONFIG" + end + + return cmd_name +end + +function get_reliability(reliable) + if reliable == 0 then + return "UDP" + else + return "TCP" + end +end + +function get_offer_type(offer) + if offer == 0 then + return "LOCAL" + elseif offer == 1 then + return "REMOTE" + elseif offer == 2 then + return "ALL" + else + return "UNKOWN" + end +end diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.pc.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.pc.in new file mode 100644 index 00000000000..f717a120d41 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB_DIR@ +includedir=@CMAKE_INSTALL_PREFIX@/include/compat + +Name: @PROJECT@ +Description: New SOME/IP stack, feature complete +Version: @VSOMEIP_VERSION@ +Libs: -L${libdir} -lvsomeip +Cflags: -I${includedir} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.xml b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.xml new file mode 100644 index 00000000000..022d625266a --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip.xml @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="1"> +<profile kind="CodeFormatterProfile" name="CommonAPI" version="1"> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="80"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_member_access" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment" value="1"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="4"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_enumerator_list" value="48"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_declarator_list" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.join_wrapped_lines" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_expression_list" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_binary_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="34"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_compact_if" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_assignment" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain" value="18"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_binary_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration" value="80"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_binary_expression" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="4"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments" value="do not insert"/> +</profile> +</profiles> diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3.pc.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3.pc.in new file mode 100644 index 00000000000..fa54522b500 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB_DIR@ +includedir=@CMAKE_INSTALL_PREFIX@/include + +Name: @PROJECT@ +Description: New SOME/IP stack, feature complete +Version: @VSOMEIP_VERSION@ +Libs: -L${libdir} -lvsomeip3 +Cflags: -I${includedir} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3Config.cmake.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3Config.cmake.in new file mode 100644 index 00000000000..d689970f4b9 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3Config.cmake.in @@ -0,0 +1,19 @@ +# Config file for the vSomeIP package, defines the following variables: +# Exports the following targets: +# vsomeip3 - CMake target for vSomeIP +# Additionally, the following variables are defined: +# VSOMEIP_LIBRARIES - list of libraries to link against, contains only +# "vsomeip3" + +# Compute paths +get_filename_component (VSOMEIP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +# Legacy variable, no longer used but kept for compatibility +get_filename_component(VSOMEIP_INCLUDE_DIRS "" PATH) + +# Our library dependencies (contains definitions for IMPORTED targets) +if (NOT TARGET vsomeip AND NOT vsomeip_BINARY_DIR) + include ("${VSOMEIP_CMAKE_DIR}/vsomeip3Targets.cmake") +endif () + +# These are IMPORTED targets created by vsomeipTargets.cmake +set (VSOMEIP_LIBRARIES vsomeip3) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3ConfigVersion.cmake.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3ConfigVersion.cmake.in new file mode 100644 index 00000000000..1c39479b1e0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeip3ConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set (PACKAGE_VERSION "@VSOMEIP_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if ("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set (PACKAGE_VERSION_COMPATIBLE FALSE) +else () + set (PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set (PACKAGE_VERSION_EXACT TRUE) + endif () +endif () diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfig.cmake.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfig.cmake.in new file mode 100644 index 00000000000..38ea7ae246c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfig.cmake.in @@ -0,0 +1,19 @@ +# Config file for the vSomeIP package, defines the following variables: +# Exports the following targets: +# vsomeip - CMake target for vSomeIP +# Additionally, the following variables are defined: +# VSOMEIP_LIBRARIES - list of libraries to link against, contains only +# "vsomeip" + +# Compute paths +get_filename_component (VSOMEIP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +# Legacy variable, no longer used but kept for compatibility +get_filename_component(VSOMEIP_INCLUDE_DIRS "" PATH) + +# Our library dependencies (contains definitions for IMPORTED targets) +if (NOT TARGET vsomeip AND NOT vsomeip_BINARY_DIR) + include ("${VSOMEIP_CMAKE_DIR}/vsomeipTargets.cmake") +endif () + +# These are IMPORTED targets created by vsomeipTargets.cmake +set (VSOMEIP_LIBRARIES vsomeip) diff --git a/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfigVersion.cmake.in b/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfigVersion.cmake.in new file mode 100644 index 00000000000..19eb60f02ba --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/vsomeipConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set (PACKAGE_VERSION "@VSOMEIP_COMPAT_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if ("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set (PACKAGE_VERSION_COMPATIBLE FALSE) +else () + set (PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set (PACKAGE_VERSION_EXACT TRUE) + endif () +endif () diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/Dockerfile b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/Dockerfile new file mode 100644 index 00000000000..99c39a9d282 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/Dockerfile @@ -0,0 +1,57 @@ +FROM ubuntu:jammy +SHELL ["/bin/bash", "-xec"] +RUN export DEBIAN_FRONTEND=noninteractive;\ + apt-get update;\ + apt-get dist-upgrade --purge --yes\ + bind9-dnsutils\ + cmake\ + g++-12\ + gdb\ + googletest\ + iproute2\ + jq\ + lcov\ + libboost-{log,system,thread}-dev\ + lsof\ + net-tools\ + ninja-build\ + openssh-server\ + pkg-config\ + python3-pip\ + tcpdump\ + valgrind\ + ;\ + apt-get autoremove --purge --yes;\ + apt-get clean;\ + pip3 install gcovr + +# Pinned GCC version +ENV CC=gcc-12 +ENV CXX=g++-12 +ENV GCOV=gcov-12 + +# Build dlt-daemon +ADD dlt-daemon /home/source +RUN cmake -B /home/build -D DLT_IPC=UNIX_SOCKET -G Ninja -S /home/source;\ + cmake --build /home/build;\ + cmake --install /home/build --prefix /usr --strip; + +# /etc configurations +RUN echo 'ECUId = M' > /etc/dlt-master.conf;\ + echo 'ECUId = S' > /etc/dlt-slave.conf;\ + echo 'SendEnv *' > /etc/ssh/ssh_config.d/vsomeip.conf;\ + echo 'AcceptEnv *' > /etc/ssh/sshd_config.d/vsomeip.conf + +# SSH configurations +RUN ssh-keygen -q -b 1024 -f ~/.ssh/id_rsa -t rsa -N '';\ + install -DTm0400 ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys;\ + install -DTm0400 ~/.ssh/id_rsa /commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub + +# Hard-coded path used in the tests' scripts +RUN ln -s /home/build /vsomeip_lib + +# Place stuff in a known place +WORKDIR /home/source + +# Declare bind-mounts +VOLUME ["/home/build", "/home/logs", "/home/source"] diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/docker-compose.yaml b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/docker-compose.yaml new file mode 100644 index 00000000000..43b77d9cb52 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/docker-compose.yaml @@ -0,0 +1,52 @@ +version: '3.7' + +networks: + ci-network-tests: + attachable: false + driver: macvlan + internal: true + ipam: + config: + - subnet: 169.254.87.0/24 + gateway: 169.254.87.254 + aux_addresses: + slave_2nd: &slave-2nd 169.254.87.42 + +x-common: + &common + build: + args: + - http_proxy + - https_proxy + - no_proxy + context: ../../.. + dockerfile: vsomeip/zuul/network-tests/Dockerfile + cap_add: + - NET_ADMIN + environment: + ENABLE_COVERAGE: ${ENABLE_COVERAGE-False} # empty to inherit from parent environment (Zuul/Ansible) + GLOBAL_TIMEOUT: 240 minutes + IP_SLAVE_2ND: *slave-2nd + SANITIZER_TYPE: ${SANITIZER_TYPE-} + STRESS_LABELS: ${STRESS_LABELS-[]} + VALGRIND_TYPE: ${VALGRIND_TYPE-} + networks: + - ci-network-tests + security_opt: + - seccomp:unconfined + ulimits: + core: -1 + volumes: + - ${SOURCE_DIR:-../..}:/home/source + - ${BUILD_DIR:-../../build}:/home/build + - ${LOGS_DIR:-../../logs}:/home/logs + +services: + master: + <<: *common + depends_on: + - slave + entrypoint: setarch -R /home/source/zuul/network-tests/entrypoint-master + slave: + <<: *common + entrypoint: setarch -R /home/source/zuul/network-tests/entrypoint-slave diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-master b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-master new file mode 100755 index 00000000000..df95c965862 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-master @@ -0,0 +1,123 @@ +#!/bin/bash -eu + +source "${BASH_SOURCE[0]%/*}"/shlib/common.shlib +source "${BASH_SOURCE[0]%/*}"/shlib/results.shlib + +ip_master=$(dig +short master) +ip_slave=$(dig +short slave) + +# Stress label extraction +# 1. We convert the incoming JSON-encoded array of labels into an object by +# using regex capture to extract the key/value from the format +# "<key> : <value>", with spaces around the colon being optional +# 2. The `stress_regex` is available on key "ctest-include" +# 3. The `stress_times` are extracted to a Bash array +# a) The value of key "ctest-stress" is split on "-" (format "N-M") +# b) Each split token is converted into a JSON number or defaults to 1 if +# conversion fails +# c) Resulting array is bumped with an extra 1 to ensure at least 2 elements +# d) Slice array to extract first 2 elements +stress_labels_json=$(jq 'map(capture("(?<key>[^:\\s]+)\\s*:\\s*(?<value>[^:\\s]+)")) | from_entries' <<< "$STRESS_LABELS") +stress_regex=$(jq -r '.["ctest-include"] // ""' <<< "$stress_labels_json") +mapfile -t stress_times < <(jq -r '.["ctest-stress"] // "1-1" | split("-") | map(try tonumber catch 1) + [1] | .[:2][]' <<< "$stress_labels_json") + +# Enable gateway mode in DLT config +echo 'GatewayMode = 1' >> /etc/dlt-master.conf +cat <<-DLT > /etc/dlt_gateway.conf + [PassiveNode1] + EcuID = S + IPaddress = $ip_slave + Timeout = 0 +DLT + +( + set -x + cmake --preset ci-network-tests \ + -D "ENABLE_${SANITIZER_TYPE}_SANITIZER=Y" \ + -D "TEST_IP_MASTER=$ip_master" \ + -D "TEST_IP_SLAVE=$ip_slave" \ + -D "VALGRIND_LOGS_DIR=/home/logs/valgrind/$VALGRIND_TYPE" \ + -D "VALGRIND_SUPPRESS_FILE=/home/source/zuul/network-tests/valgrind/$VALGRIND_TYPE.supp" \ + -D "VALGRIND_TYPE=$VALGRIND_TYPE" + cmake --build --preset ci-network-tests +) + +tests_result_file=/home/logs/tests_result.json +declare -i valgrind_errors=0 +mkdir -p /home/logs/{cores,coverage,dlt,{,failed-}junit,pcap,"valgrind/$VALGRIND_TYPE"} +gen-result-file "$tests_result_file" "/home/source/.tests-whitelist" + +for ((n = 0; n < stress_times[0]; n++)) +do + for test in $(ctest --preset ci-network-tests --show-only=json-v1 ${stress_regex:+--tests-regex "$stress_regex"} | jq -r '.tests[].name') + do + for ((m = 0; m < stress_times[1]; m++)) + do + if is-timed-out + then + break + fi + + run-both rm -f /tmp/vsomeip* + run-both dlt-daemon -c /etc/dlt-@name@.conf -d + dlt-receive -o /home/logs/dlt/"$test".dlt localhost & + tcpdump -U -i eth0 -w /home/logs/pcap/"$test".pcap & + + if ! ctest --preset ci-network-tests --output-junit /home/logs/junit/"$test".xml --tests-regex "^$test$" --test-output-size-passed 10485760 --test-output-size-failed 10485760 + then + update-result-file "$tests_result_file" "$test" 1 + cp /home/logs/{junit/"$test".xml,failed-junit/} + else + valgrind_errors=$(valgrind-errors "/home/logs/valgrind/$VALGRIND_TYPE" "$test") + if ((valgrind_errors > 0)) + then + update-result-file "$tests_result_file" "$test" "$valgrind_errors" "$VALGRIND_TYPE" + cp /home/logs/{junit/"$test".xml,failed-junit/} + else + update-result-file "$tests_result_file" "$test" + fi + fi + + kill %1 + kill -USR2 %2 || : + kill -INT %2 || : + run-both pkill -TERM dlt-daemon || : + run-both pidwait dlt-daemon || : + run-both kill -KILL -1 || : + done + done +done + +( + cd /home/logs + tar -acvf junit.tgz --transform=s/^junit/network-tests/ junit/*.xml + shopt -s nullglob + if [[ "$(echo failed-junit/*.xml)" ]] + then + tar -acvf failed-junit.tgz --transform=s/^failed-junit/network-tests/ failed-junit/*.xml + fi +) + +gen-core-backtraces /home/logs/cores + +if [ "$ENABLE_COVERAGE" != False ] +then + run-both gcovr --gcov-executable "$GCOV" --json /home/logs/coverage/@name@.json --root /home/source /home/build + run-both lcov --base-directory /home/source --capture --directory /home/build --gcov-tool "$GCOV" --output-file /home/logs/coverage/@name@.info + gcovr --add-tracefile=/home/logs/coverage/{master,slave}.json --json /home/logs/coverage.json + lcov --add-tracefile=/home/logs/coverage/{master,slave}.info --output-file /home/logs/coverage/merged.info + lcov --remove /home/logs/coverage/merged.info '/usr/*' --output-file /home/logs/coverage/filtered.info + genhtml --output-directory /home/logs/coverage/html --prefix /home/source /home/logs/coverage/filtered.info +fi + +run-slave kill 1 || : + +print-results "$tests_result_file" +if is-timed-out +then + echo 'Global timeout was reached!' + echo 'See above which test(s) were at fault.' + exit 255 +else + exit "$(jq '.exit_error' "$tests_result_file")" +fi diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-slave b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-slave new file mode 100755 index 00000000000..34ba68d5f4e --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/entrypoint-slave @@ -0,0 +1,6 @@ +#!/bin/bash -eu + +source "${BASH_SOURCE[0]%/*}"/shlib/common.shlib + +mkdir -p /run/sshd +exec /sbin/sshd -D diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/common.shlib b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/common.shlib new file mode 100644 index 00000000000..229cd36c004 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/common.shlib @@ -0,0 +1,49 @@ +#!/usr/bin/echo non-executable-shell-library +# shellcheck shell=bash + +# Detect build timeout +function is-timed-out +{ + declare -gi stop_time + if [[ ! -v stop_time ]] + then + stop_time=$(date -d "$GLOBAL_TIMEOUT" +%s) + readonly stop_time + fi + (($(date +%s) >= stop_time)) +} + +# Run a command on the slave container +function run-slave +{ + ssh -no StrictHostKeyChecking=no slave -- "${@@Q}" +} + +# Run a command on both containers +function run-both +{ + local -A commands=( + [master]=exec + [slave]=run-slave + ) + local name + for name in master slave + do + ("${commands[$name]}" "${@//@name@/"$name"}") + done +} + +# Pretty-print a list of items +function print-list +{ + echo "$1: $(($#-1))" + shift + local elem + for elem + do + echo "- $elem" + done +} + +# Add multicast route +ip route add multicast 224.0.0.0/4 dev eth0 diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/results.shlib b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/results.shlib new file mode 100644 index 00000000000..20c577c6a93 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/shlib/results.shlib @@ -0,0 +1,83 @@ +#!/usr/bin/echo non-executable-shell-library +# shellcheck shell=bash + +function gen-result-file +{ + local result_file="$1" + local whitelist_file="$2" + whitelist=$(jq --null-input --rawfile list "$whitelist_file" '$list | split("\n") | map(select(test("^(#|$)") | not))') + jq --argjson whitelist "$whitelist" \ + -n '{executed_tests: [], failures: [], exit_error: 0, whitelist: $whitelist}'\ + > "$result_file" +} + +function update-result-file +{ + local result_file="$1" + local test_name="$2" + local errors=${3:-0} + local reason="${4:-}" + + status=$( ((errors > 0)) && echo "failed" || echo "passed" ) + data=$(jq '.executed_tests += [{name: $test_name, status: $status, reason: $reason}]'\ + --arg test_name "$test_name"\ + --arg status "$status"\ + --arg reason "$reason"\ + < "$result_file") + if ((errors > 0)) + then + test_label="$test_name" + if [[ "$reason" ]] + then + test_label+=" ($errors $reason error(s))" + fi + # Check if the test is whitelisted + if jq --arg test_name "$test_name" --exit-status '[.whitelist[] | select(. == $test_name)] | length > 0' "$result_file" + then + test_label+=" (whitelisted)" + else + data=$(jq '.exit_error += 1' <<< "$data") + fi + data=$(jq '.failures += [$test_label]' --arg test_label "$test_label" <<< "$data") + fi + echo "$data" > "$result_file" +} + +function valgrind-errors +{ + local outputs_folder="$1" + local test_name="$2" + + output_file="$outputs_folder/$test_name.out" + if [[ ! -f "$output_file" || -d "$output_file" ]] + then + echo 0 + return + fi + (grep -oP 'ERROR SUMMARY: \K\d+' "$output_file" || echo 0) | sort -n | tail -n1 +} + +function gen-core-backtraces +{ + local outputs_folder="$1" + shopt -s nullglob + for core in /tmp/core.* + do + prog=${core#/tmp/core.} + prog=${prog//!/\/} + gdb -ex 'thread apply all bt' -ex 'set pagination 0' -batch "$prog" "$core" | tee "$outputs_folder/backtrace.${prog##*/}" + cp -v "$core" "$outputs_folder/core.${prog##*/}" + done + shopt -u nullglob +} + +function print-results +{ + local result_file="$1" + executed_tests=$(jq '.executed_tests | length' "$result_file") + declare failed_tests=() + mapfile -t failed_tests < <(jq -r '.failures[]' "$result_file") + echo '[Execution summary]' + echo "Passed tests: $((executed_tests - ${#failed_tests[@]})) of $executed_tests" + print-list 'Failed tests' "${failed_tests[@]}" +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/helgrind.supp b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/helgrind.supp new file mode 100644 index 00000000000..103dd676e0c --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/helgrind.supp @@ -0,0 +1,24 @@ +{ + libdlt_unlocked + Helgrind:UnlockUnlocked + ... + obj:/usr/lib/libdlt.so.* +} +{ + libdlt_unlocked2 + Helgrind:UnlockForeign + ... + obj:/usr/lib/libdlt.so.* +} +{ + libdlt_pthAPIerror + Helgrind:PthAPIerror + ... + obj:/usr/lib/libdlt.so.* +} +{ + libdlt_misc + Helgrind:Misc + ... + obj:/usr/lib/libdlt.so.* +} diff --git a/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/memcheck.supp b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/memcheck.supp new file mode 100644 index 00000000000..b3989b427f0 --- /dev/null +++ b/lib/libsomeip-c/vsomeip-3.5.1/zuul/network-tests/valgrind/memcheck.supp @@ -0,0 +1,26 @@ +{ + <memcheck_leak_bash_if_command> + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:make_if_command + fun:yyparse + fun:parse_command + fun:read_command + fun:reader_loop + fun:main +} +{ + <memcheck_leak_libdlt> + Memcheck:Leak + match-leak-kinds: possible + ... + fun:dlt_init +} +{ + <memcheck_leak_libc> + Memcheck:Leak + match-leak-kinds: definite + ... + fun:__libc_dlopen_mode +} diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index deb24958038..1d64b5fbea5 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -283,6 +283,10 @@ REGISTER_IN_PLUGIN("in_lib") REGISTER_IN_PLUGIN("in_forward") REGISTER_IN_PLUGIN("in_random") +if(FLB_IN_SOMEIP) + REGISTER_IN_PLUGIN("in_someip") +endif() + # PROCESSORS # ========== REGISTER_PROCESSOR_PLUGIN("processor_content_modifier") diff --git a/plugins/in_someip/CMakeLists.txt b/plugins/in_someip/CMakeLists.txt new file mode 100644 index 00000000000..7da6895b183 --- /dev/null +++ b/plugins/in_someip/CMakeLists.txt @@ -0,0 +1,4 @@ +set(src in_someip.c + in_someip_config.c) + +FLB_PLUGIN(in_someip "${src}" "someip-c") diff --git a/plugins/in_someip/in_someip.c b/plugins/in_someip/in_someip.c new file mode 100644 index 00000000000..c7932371c41 --- /dev/null +++ b/plugins/in_someip/in_someip.c @@ -0,0 +1,847 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "in_someip.h" + +#include "in_someip_config.h" + +#include <fluent-bit/flb_base64.h> +#include <fluent-bit/flb_input_plugin.h> +#include <fluent-bit/flb_log_event_encoder.h> + +/* Messages sent over the notify pipe */ +#define IN_SOMEIP_EVENT_RECEIVED 1 + +/* Messages sent over the RPC pipe */ +#define IN_SOMEIP_SERVICE_AVAILABLE 1 +#define IN_SOMEIP_RESPONSE_RECEIVED 2 + +/* Data sent over the RPC pipe */ + +/* Structure sent after SERVICE_AVAILABLE */ +struct in_someip_service_available +{ + uint16_t service_id; + uint16_t instance_id; + int available_flag; +}; + +/* For RESPONSE_RECEIVED the some_ip_request_id is sent over the pipe */ + +/* + * Base64 encode a binary buffer + * + * @param ctx Plugin context + * @param binary_len Size of the binary buffer to encode + * @param binary_data Pointer to binary data to encode + * @param encoded_buffer Pointer to buffer to hold the base64 encoded data. + * Note: Caller should call flb_sds_destroy on the encoded + * buffer after using it. + */ +static void +encode_bytes(struct flb_someip *ctx, size_t binary_len, + uint8_t *binary_data, flb_sds_t *encoded_buffer) +{ + size_t encoded_buffer_size = (binary_len * 4); + size_t encoded_len; + + if (binary_data != NULL && binary_len > 0) { + *encoded_buffer = flb_sds_create_size(encoded_buffer_size); + if (0 + != flb_base64_encode((unsigned char *) (*encoded_buffer), + encoded_buffer_size, &encoded_len, + (unsigned char *) binary_data, binary_len)) { + flb_plg_warn(ctx->ins, "Failed to encode binary data"); + } + else { + flb_plg_debug(ctx->ins, "Encoded event: %s", *encoded_buffer); + } + } + else { + flb_plg_debug(ctx->ins, "No data to encode"); + } +} + +/* + * Callback function when a SOME/IP event is received + * + * @param data The flb_someip context pointer + * + */ +static void in_someip_event_notification(void *data) +{ + struct flb_someip *ctx; + ssize_t written; + uint8_t command; + + ctx = data; + if (NULL != ctx) { + command = IN_SOMEIP_EVENT_RECEIVED; + written = + flb_pipe_write_all(ctx->notify_pipe_fd[1], &command, + sizeof(command)); + if (written < 0) { + flb_errno(); + } + } +} + +/* + * Callback function when a SOME/IP Service availability is updated + * + * @param data The flb_someip context pointer + * @param service The service identifier + * @param instance The service instance + * @param available The availability indication + * + */ +static void +in_someip_avail_handler(void *data, uint16_t service, + uint16_t instance, int available) +{ + struct flb_someip *ctx; + ssize_t written; + uint8_t command; + struct in_someip_service_available avail_indication; + + ctx = data; + if (NULL != ctx) { + command = IN_SOMEIP_SERVICE_AVAILABLE; + written = + flb_pipe_write_all(ctx->rpc_pipe_fd[1], &command, + sizeof(command)); + if (written < 0) { + flb_errno(); + } + avail_indication.service_id = service; + avail_indication.instance_id = instance; + avail_indication.available_flag = available; + written = flb_pipe_write_all(ctx->rpc_pipe_fd[1], &avail_indication, + sizeof(avail_indication)); + if (written < 0) { + flb_errno(); + } + } +} + +/* + * Callback function when a SOME/IP RPC response is received + * + * @param data The flb_someip context pointer + * @param request_id Pointer to the structure identifying the request + * + */ +static void +in_someip_response_callback(void *data, + const struct some_ip_request_id *request_id) +{ + struct flb_someip *ctx; + ssize_t written; + uint8_t command; + + ctx = data; + if (NULL != ctx && request_id != NULL) { + flb_plg_trace(ctx->ins, "Response received, client ID = %d", + request_id->client_request_id); + command = IN_SOMEIP_RESPONSE_RECEIVED; + written = + flb_pipe_write_all(ctx->rpc_pipe_fd[1], &command, + sizeof(command)); + if (written < 0) { + flb_errno(); + } + written = flb_pipe_write_all(ctx->rpc_pipe_fd[1], request_id, + sizeof(struct some_ip_request_id)); + if (written < 0) { + flb_errno(); + } + } +} + +/* + * Function to subscribe to the configured SOME/IP events + * + * @param ctx The plugin context + * + * @return int 0 on success, -1 on failure + */ +static void in_someip_subscribe_for_someip_events(struct flb_someip *ctx) +{ + struct cfl_list *tmp; + struct cfl_list *head; + struct in_someip_event_identifier *an_event; + + cfl_list_foreach_safe(head, tmp, &(ctx->someip_events)) { + an_event = + cfl_list_entry(head, struct in_someip_event_identifier, _head); + if (someip_subscribe_event(ctx->someip_client_id, + an_event->service_id, + an_event->instance_id, + an_event->event_id, + an_event->event_groups, + an_event->number_of_event_groups, + ctx, + in_someip_event_notification) != SOMEIP_RET_SUCCESS) { + flb_plg_error(ctx->ins, + "Failed to subscribe for service = %d, instance = %d, event %d", + an_event->service_id, an_event->instance_id, + an_event->event_id); + } + else { + flb_plg_debug(ctx->ins, + "Subscribed for service = %d, instance = %d, event %d", + an_event->service_id, an_event->instance_id, + an_event->event_id); + } + } +} + +/* + * Function to request the services we need for performing RPC + * + * @param ctx The plugin context + * + * @return int 0 on success, -1 on failure + */ +static void in_someip_request_services(struct flb_someip *ctx) +{ + struct cfl_list *tmp; + struct cfl_list *head; + struct in_someip_rpc *an_rpc; + + cfl_list_foreach_safe(head, tmp, &(ctx->someip_pending_rpc)) { + an_rpc = cfl_list_entry(head, struct in_someip_rpc, _head); + if (someip_request_service(ctx->someip_client_id, + an_rpc->service_id, + an_rpc->instance_id, + ctx, + in_someip_avail_handler) != SOMEIP_RET_SUCCESS) { + flb_plg_error(ctx->ins, + "Failed to request service = %d, instance = %d", + an_rpc->service_id, an_rpc->instance_id); + } + else { + flb_plg_debug(ctx->ins, "Requested service = %d, instance = %d", + an_rpc->service_id, an_rpc->instance_id); + } + } +} + +/* + * Function to generate a record when a SOME/IP event is received + * + * @param ctx The plugin context + * @param event The SOME/IP event data + * + * @return 0 on success, -1 on an error + */ +static int +in_someip_generate_someip_event_record(struct flb_someip *ctx, + struct some_ip_event *event) +{ + struct flb_log_event_encoder *log_encoder = ctx->log_encoder; + int encoder_result; + int ret; + flb_sds_t base64_buffer; + + flb_plg_debug(ctx->ins, + "Received event {%d, %d} with payload of %zu bytes", + event->service_id, event->event_id, event->event_len); + + encoder_result = flb_log_event_encoder_begin_record(log_encoder); + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_set_current_timestamp(log_encoder); + } + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("record type"), + FLB_LOG_EVENT_CSTRING_VALUE + ("event"))} + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("service"), + FLB_LOG_EVENT_UINT16_VALUE + (event->service_id))} + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("instance"), + FLB_LOG_EVENT_UINT16_VALUE + (event->instance_id))} + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("event"), + FLB_LOG_EVENT_UINT16_VALUE + (event->event_id))} + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + if (event->event_len > 0) { + encode_bytes(ctx, event->event_len, event->event_data, + &base64_buffer); + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("payload"), + FLB_LOG_EVENT_CSTRING_VALUE + (base64_buffer)) + flb_sds_destroy(base64_buffer); + } + else { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("payload"), + FLB_LOG_EVENT_CSTRING_VALUE + ("")) + } + } + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = flb_log_event_encoder_commit_record(log_encoder); + } + + if (encoder_result != FLB_EVENT_ENCODER_SUCCESS) { + flb_log_event_encoder_rollback_record(log_encoder); + } + + flb_plg_trace(ctx->ins, "Event encoding result = %d", encoder_result); + if (event->event_data != NULL) { + free(event->event_data); + event->event_data = NULL; + } + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + if (ctx->log_encoder->output_length > 0) { + flb_input_log_append(ctx->ins, NULL, 0, + ctx->log_encoder->output_buffer, + ctx->log_encoder->output_length); + } + ret = 0; + } + else { + flb_plg_error(ctx->ins, "Error encoding record : %d", encoder_result); + ret = -1; + } + + flb_log_event_encoder_reset(ctx->log_encoder); + return ret; +} + +/* + * Function to generate a record when a SOME/IP response is received + * + * @param ctx The plugin context + * @param response The SOME/IP response data + * + * @return 0 on success, -1 on an error + */ +static int +in_someip_generate_someip_response_record(struct flb_someip *ctx, + struct some_ip_response *response) +{ + struct flb_log_event_encoder *log_encoder = ctx->log_encoder; + struct some_ip_request_id *request_ptr = &response->request_id; + int ret; + int encoder_result; + flb_sds_t base64_buffer; + + flb_plg_debug(ctx->ins, + "Received response for {%d, %d, %d}, length = %ld", + response->request_id.service_id, + response->request_id.instance_id, response->method_id, + response->payload_len); + + encoder_result = flb_log_event_encoder_begin_record(log_encoder); + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_set_current_timestamp(log_encoder); + } + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("record type"), + FLB_LOG_EVENT_CSTRING_VALUE + ("response"))} + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("service"), + FLB_LOG_EVENT_UINT16_VALUE + (request_ptr->service_id))} + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("instance"), + FLB_LOG_EVENT_UINT16_VALUE + (request_ptr->instance_id))} + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("method"), + FLB_LOG_EVENT_UINT16_VALUE + (response->method_id))} + + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + if (response->payload_len > 0 && response->payload != NULL) { + encode_bytes(ctx, response->payload_len, response->payload, + &base64_buffer); + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("payload"), + FLB_LOG_EVENT_CSTRING_VALUE + (base64_buffer)) + flb_sds_destroy(base64_buffer); + } + else { + encoder_result = + flb_log_event_encoder_append_body_values(log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE + ("payload"), + FLB_LOG_EVENT_CSTRING_VALUE + ("")) + } + } + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + encoder_result = flb_log_event_encoder_commit_record(log_encoder); + } + + if (encoder_result != FLB_EVENT_ENCODER_SUCCESS) { + flb_log_event_encoder_rollback_record(log_encoder); + } + + flb_plg_trace(ctx->ins, "Response encoding result = %d", encoder_result); + if (response->payload != NULL) { + free(response->payload); + response->payload = NULL; + } + if (encoder_result == FLB_EVENT_ENCODER_SUCCESS) { + if (ctx->log_encoder->output_length > 0) { + flb_input_log_append(ctx->ins, NULL, 0, + ctx->log_encoder->output_buffer, + ctx->log_encoder->output_length); + } + ret = 0; + } + else { + flb_plg_error(ctx->ins, "Error encoding record : %d", encoder_result); + ret = -1; + } + + flb_log_event_encoder_reset(ctx->log_encoder); + return ret; +} + +/* + * Function used when the RPC collector gets an event to indicate that a service + * has become available (or unavailable) + */ +static void in_someip_handle_avail_event(struct flb_someip *ctx) +{ + struct cfl_list *tmp; + struct cfl_list *head; + ssize_t bytes_read; + struct in_someip_service_available serv_available; + struct in_someip_rpc *an_rpc; + struct some_ip_request request; + struct in_someip_response *an_response; + + // Pull the service availability off the pipe + bytes_read = flb_pipe_read_all(ctx->rpc_pipe_fd[0], &serv_available, + sizeof(serv_available)); + if (bytes_read <= 0) { + flb_errno(); + return; + } + + flb_plg_debug(ctx->ins, "Service = %d, Instance = %d, available = %d", + serv_available.service_id, serv_available.instance_id, + serv_available.available_flag); + + // If the service is available, and we have pending RPC, send the request + if (SOMEIP_SERVICE_AVAILABLE == serv_available.available_flag) { + cfl_list_foreach_safe(head, tmp, &ctx->someip_pending_rpc) { + an_rpc = cfl_list_entry(head, struct in_someip_rpc, _head); + if (an_rpc->service_id == serv_available.service_id + && an_rpc->instance_id == serv_available.instance_id) { + request.request_id.service_id = an_rpc->service_id; + request.request_id.instance_id = an_rpc->instance_id; + + // Will be overwritten on success + request.request_id.client_request_id = 0; + request.method_id = an_rpc->method_id; + request.payload_len = an_rpc->payload_len; + request.payload = an_rpc->payload; + if (SOMEIP_RET_SUCCESS + == someip_send_request(ctx->someip_client_id, &request, + ctx, in_someip_response_callback)) + { + flb_plg_debug(ctx->ins, "Sent request method = %d", + an_rpc->method_id); + an_response = flb_malloc(sizeof(struct in_someip_response)); + if (NULL == an_response) { + flb_errno(); + return; + } + an_response->response.request_id = request.request_id; + an_response->response.method_id = request.method_id; + an_response->response.payload = NULL; + an_response->response.payload_len = 0; + cfl_list_add(&an_response->_head, + &ctx->someip_waiting_response); + } + else { + flb_plg_error(ctx->ins, + "Failed to send request for method %d", + an_rpc->method_id); + } + if (an_rpc->payload != NULL) { + flb_free(an_rpc->payload); + } + cfl_list_del(&an_rpc->_head); + flb_free(an_rpc); + } + } + } +} + +/* + * Function use to handle a response for an RPC + */ +static void in_someip_handle_response_event(struct flb_someip *ctx) +{ + struct cfl_list *tmp; + struct cfl_list *head; + ssize_t bytes_read; + struct some_ip_request_id received_request_id; + struct some_ip_request_id *pending_request_id; + struct in_someip_response *an_response; + int ret; + + // Pull the request id off of the pipe + bytes_read = flb_pipe_read_all(ctx->rpc_pipe_fd[0], &received_request_id, + sizeof(received_request_id)); + if (bytes_read <= 0) { + flb_errno(); + return; + } + + flb_plg_debug(ctx->ins, + "Response received for Service = %d, Instance = %d, Client Request = " + "0x%08x", + received_request_id.service_id, + received_request_id.instance_id, + received_request_id.client_request_id); + + /* Find the entry that matches this response */ + cfl_list_foreach_safe(head, tmp, &ctx->someip_waiting_response) { + an_response = cfl_list_entry(head, struct in_someip_response, _head); + pending_request_id = &(an_response->response.request_id); + flb_plg_trace(ctx->ins, "Checking waiting response {%d, %d, 0x%08x}", + pending_request_id->service_id, + pending_request_id->instance_id, + pending_request_id->client_request_id); + if (pending_request_id->service_id == received_request_id.service_id + && pending_request_id->instance_id == + received_request_id.instance_id + && pending_request_id->client_request_id == + received_request_id.client_request_id) { + + // Retrieve the response + ret = someip_get_response(ctx->someip_client_id, + &an_response->response); + if (ret != SOMEIP_RET_SUCCESS) { + flb_plg_error(ctx->ins, + "Failed to retrieve response for service = %d, instance " + "%d, client_request = %d, error = %d", + received_request_id.service_id, + received_request_id.instance_id, + received_request_id.client_request_id, ret); + } + else { + in_someip_generate_someip_response_record(ctx, + &an_response->response); + } + cfl_list_del(&an_response->_head); + flb_free(an_response); + return; + } + } + flb_plg_warn(ctx->ins, "Did not find request {%d, %d, 0x%08x}", + received_request_id.service_id, + received_request_id.instance_id, + received_request_id.client_request_id); +} + +/* + * Function called when a SOME/IP notification is received (event) + * + * @param in Pointer to the Fluent Bit input instance + * @param config Not used + * @param in_context Pointer to the Fluent Bit context + */ +static int +in_someip_collect_notify(struct flb_input_instance *in, + struct flb_config *config, void *in_context) +{ + int ret; + int keep_reading; + int someip_result; + uint8_t val; + struct flb_someip *context; + struct some_ip_event event_data; + + (void) config; + context = (struct flb_someip *) in_context; + + // Pull the byte off of the notify pipe + ret = flb_pipe_r(context->notify_pipe_fd[0], (char *) &val, sizeof(val)); + if (ret <= 0) { + flb_errno(); + return -1; + } + + flb_plg_debug(in, "collect called"); + + /* Pull events from SOME/IP until there aren't any */ + keep_reading = 1; + while (keep_reading) { + someip_result = someip_get_next_event(context->someip_client_id, &event_data); + if (someip_result == SOMEIP_RET_SUCCESS) { + ret = + in_someip_generate_someip_event_record(context, &event_data); + } + else if (someip_result == SOMEIP_RET_NO_EVENT_AVAILABLE) { + ret = 0; + keep_reading = 0; + } + else { + ret = -1; + keep_reading = 0; + } + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + keep_reading = 0; + ret = -1; + } + } + + return ret; +} + +/* + * Function called when a SOME/IP RPC related message is available + * + * @param in Pointer to the Fluent Bit input instance + * @param config Not used + * @param in_context Pointer to the Fluent Bit context + */ +static int +in_someip_collect_rpc(struct flb_input_instance *in, + struct flb_config *config, void *in_context) +{ + int ret; + uint8_t val; + struct flb_someip *context; + + (void) config; + + context = (struct flb_someip *) in_context; + + // Pull the byte off of the rpc pipe + ret = flb_pipe_r(context->rpc_pipe_fd[0], (char *) &val, sizeof(val)); + if (ret <= 0) { + flb_errno(); + return -1; + } + + flb_plg_debug(in, "collect rpc called"); + + if (val == IN_SOMEIP_SERVICE_AVAILABLE) { + in_someip_handle_avail_event(context); + } + else if (val == IN_SOMEIP_RESPONSE_RECEIVED) { + in_someip_handle_response_event(context); + } + + return 0; +} + +/* + * Callback function to initialize SOME/IP plugin + * + * @param ins Pointer to flb_input_instance + * @param config Pointer to flb_config + * @param data Unused + * + * @return int 0 on success, -1 on failure + */ +static int +in_someip_init(struct flb_input_instance *in, + struct flb_config *config, void *data) +{ + int ret; + struct flb_someip *ctx = NULL; + (void) data; + (void) config; + + /* Allocate and initialize the configuration */ + ctx = in_someip_config_init(in); + if (ctx == NULL) { + return -1; + } + + if (someip_initialize("in_someip", &(ctx->someip_client_id)) == + SOMEIP_RET_FAILURE) { + flb_plg_error(in, "Could not initialize SOME/IP library"); + in_someip_config_destroy(ctx); + return -1; + } + + ctx->log_encoder = + flb_log_event_encoder_create(FLB_LOG_EVENT_FORMAT_DEFAULT); + if (ctx->log_encoder == NULL) { + flb_plg_error(in, "Could not initialize log encoder"); + someip_shutdown(ctx->someip_client_id); + in_someip_config_destroy(ctx); + return -1; + } + + in_someip_subscribe_for_someip_events(ctx); + in_someip_request_services(ctx); + + flb_plg_debug(in, "Initialized SOME/IP library"); + + flb_input_set_context(in, ctx); + + /* Register an event collector for subscription notifications */ + ret = flb_input_set_collector_event(in, in_someip_collect_notify, + ctx->notify_pipe_fd[0], config); + if (ret == -1) { + someip_shutdown(ctx->someip_client_id); + in_someip_config_destroy(ctx); + return -1; + } + + ctx->coll_fd_notify = ret; + + ret = + flb_input_set_collector_event(in, in_someip_collect_rpc, + ctx->rpc_pipe_fd[0], config); + if (ret == -1) { + someip_shutdown(ctx->someip_client_id); + in_someip_config_destroy(ctx); + return -1; + } + + ctx->coll_fd_rpc = ret; + + return 0; +} + +/* + * Callback used by Fluent Bit to pause collection of data + * + * @param data Pointer to the plugin context + * @param config not used + */ +static void in_someip_pause(void *data, struct flb_config *config) +{ + struct flb_someip *ctx = data; + (void) config; + + /* + * Pause collectors + */ + flb_input_collector_pause(ctx->coll_fd_notify, ctx->ins); + flb_input_collector_pause(ctx->coll_fd_rpc, ctx->ins); +} + +/* + * Callback used by Fluent Bit to resume collection of data + * + * @param data Pointer to the plugin context + * @param config Not used + */ +static void in_someip_resume(void *data, struct flb_config *config) +{ + struct flb_someip *ctx = data; + (void) config; + + /* + * Resume collectors + */ + flb_input_collector_resume(ctx->coll_fd_notify, ctx->ins); + flb_input_collector_resume(ctx->coll_fd_rpc, ctx->ins); +} + +/* + * Callback used by Fluent Bit when shutting down + */ +static int in_someip_exit(void *data, struct flb_config *config) +{ + (void) *config; + struct flb_someip *ctx = data; + + flb_plg_info(ctx->ins, "Shutting down in_someip"); + someip_shutdown(ctx->someip_client_id); + if (ctx->log_encoder) { + flb_log_event_encoder_destroy(ctx->log_encoder); + } + in_someip_config_destroy(ctx); + + return 0; +} + +/* Configuration properties map */ +static struct flb_config_map config_map[] + = { {FLB_CONFIG_MAP_CLIST_4, "Event", NULL, FLB_CONFIG_MAP_MULT, FLB_TRUE, + offsetof(struct flb_someip, events), + "SOME/IP Event/Field to subscribe. " + "Format: `Event <service id>,<instance id>,<event id>,<event group 1>,...`"}, +{FLB_CONFIG_MAP_CLIST_3, "RPC", NULL, FLB_CONFIG_MAP_MULT, FLB_TRUE, + offsetof(struct flb_someip, rpcs), + "RPC to send at start up. " + "Format: `RPC <service id>,<instance id>,<method id>,<Base64 encoded " + "payload>`"}, +{0} +}; + +struct flb_input_plugin in_someip_plugin = {.name = "someip", + .description = "Interact with SOME/IP services as a client", + .cb_init = in_someip_init, + .cb_pre_run = NULL, + .cb_collect = NULL, + .cb_flush_buf = NULL, + .config_map = config_map, + .cb_pause = in_someip_pause, + .cb_resume = in_someip_resume, + .cb_exit = in_someip_exit +}; diff --git a/plugins/in_someip/in_someip.h b/plugins/in_someip/in_someip.h new file mode 100644 index 00000000000..18640ad720f --- /dev/null +++ b/plugins/in_someip/in_someip.h @@ -0,0 +1,115 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FLB_IN_SOMEIP_H +#define FLB_IN_SOMEIP_H + +#include <cfl/cfl.h> +#include <cfl/cfl_list.h> +#include <fluent-bit/flb_input.h> +#include <someip_api.h> +#include <stdint.h> + +/* + * Structure for events that we want to subscribe to + */ +struct in_someip_event_identifier +{ + /* SOME/IP Service ID */ + uint16_t service_id; + /* SOME/IP Service instance ID */ + uint16_t instance_id; + /* SOME/IP Event ID */ + uint16_t event_id; + /* Array of SOME/IP Event Groups */ + uint16_t *event_groups; + /* Number of Event Groups */ + size_t number_of_event_groups; + /* Needed to store this in a cfl_list */ + struct cfl_list _head; +}; + +/* + * Structure for pending RPC we want to perform + */ +struct in_someip_rpc +{ + /* SOME/IP Service ID */ + uint16_t service_id; + /* SOME/IP Service instance ID */ + uint16_t instance_id; + /* SOME/IP Method ID */ + uint16_t method_id; + /* Length of the request payload */ + size_t payload_len; + /* Request payload contents */ + uint8_t *payload; + + /* Needed to store this in a cfl_list */ + struct cfl_list _head; +}; + +/* + * Structure for RPC that we are waiting for responses + */ +struct in_someip_response +{ + /* Structure with the SOME/IP response data */ + struct some_ip_response response; + /* Needed to store this in a cfl_list */ + struct cfl_list _head; +}; + +/* + * Structure holes the configuration and data for this plugin + */ +struct flb_someip +{ + /* FLB input plugin instance */ + struct flb_input_instance *ins; + + /* Pipe used to communicate when a SOME/IP notification (i.e for SOME/IP event) has + * been received */ + flb_pipefd_t notify_pipe_fd[2]; + + /* Pipe used to communicate when a RPC event has happened */ + flb_pipefd_t rpc_pipe_fd[2]; + + /* Configuration */ + struct mk_list *events; + struct mk_list *rpcs; + + /* SOME/IP client identifier */ + uint16_t someip_client_id; + + /* Holds the SOME/IP events that we are subscribed to */ + struct cfl_list someip_events; + + /* Holds the SOME/IP RPC that we want to perform */ + struct cfl_list someip_pending_rpc; + + /* Holds the SOME/IP RPC where request has been sent and waiting for a response */ + struct cfl_list someip_waiting_response; + + /* Collectors */ + int coll_fd_notify; + int coll_fd_rpc; + + /* Log Encoder */ + struct flb_log_event_encoder *log_encoder; +}; + +#endif diff --git a/plugins/in_someip/in_someip_config.c b/plugins/in_someip/in_someip_config.c new file mode 100644 index 00000000000..015ad82e45b --- /dev/null +++ b/plugins/in_someip/in_someip_config.c @@ -0,0 +1,388 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "in_someip_config.h" + +#include <fluent-bit/flb_base64.h> +#include <fluent-bit/flb_input_plugin.h> + +/* + * Function to add an SOME/IP event to the cfl_list + * @param ctx Pointer to the plugin context + * @param service SOME/IP Service ID + * @param service SOME/IP Service instance ID + * @param event SOME/IP event ID + * @param num_event_groups Number of event groups + * @param prev Pointer to the previous configuration list item + * @param mv Pointer to the configuration map + * + * @return 0 on SUCCESS, -1 on failure + */ +static int +in_someip_add_event(struct flb_someip *ctx, uint16_t service, + uint16_t instance, uint16_t event, + const size_t num_event_groups, + struct mk_list *prev, struct flb_config_map_val *mv) +{ + struct in_someip_event_identifier *an_event; + struct flb_slist_entry *event_group; + int i; + + flb_plg_trace(ctx->ins, + "Adding event {%d, %d, %d} to the subscription list", + service, instance, event); + an_event = flb_malloc(sizeof(struct in_someip_event_identifier)); + if (an_event == NULL) { + flb_errno(); + return -1; + } + an_event->service_id = service; + an_event->instance_id = instance; + an_event->event_id = event; + + /* Allocate memory to store the event group list */ + an_event->event_groups = flb_malloc(num_event_groups * sizeof(uint16_t)); + if (an_event->event_groups == NULL) { + flb_errno(); + flb_free(an_event); + return -1; + } + /* Populate the event group array */ + for (i = 0; i < num_event_groups; ++i) { + event_group = + mk_list_entry_next(prev, struct flb_slist_entry, _head, + mv->val.list); + if (event_group != NULL) { + an_event->event_groups[i] = atoi(event_group->str); + flb_plg_trace(ctx->ins, + "Including event group {%d} for the event", + an_event->event_groups[i]); + prev = &event_group->_head; + } + } + an_event->number_of_event_groups = num_event_groups; + cfl_list_add(&(an_event->_head), &ctx->someip_events); + return 0; +} + +/* + * Function to add an SOME/IP RPC to the cfl_list + * + * @param ctx Pointer to the plugin context + * @param service SOME/IP Service ID + * @param service SOME/IP Service instance ID + * @param event SOME/IP Method ID + * @param message Message to send in the request + * + * @return 0 on SUCCESS, -1 on failure + */ +static int +in_someip_add_rpc(struct flb_someip *ctx, uint16_t service, + uint16_t instance, uint16_t method, flb_sds_t message) +{ + struct in_someip_rpc *an_rpc; + flb_sds_t decoded_buffer; + size_t decoded_len; + size_t encoded_len; + + flb_plg_trace(ctx->ins, "Adding RPC {%d, %d, %d} to the pending list", + service, instance, method); + an_rpc = flb_malloc(sizeof(struct in_someip_rpc)); + if (an_rpc == NULL) { + flb_errno(); + return -1; + } + an_rpc->service_id = service; + an_rpc->instance_id = instance; + an_rpc->method_id = method; + encoded_len = flb_sds_len(message); + if (encoded_len > 0) { + decoded_buffer = flb_sds_create_size(encoded_len); + if (0 + != flb_base64_decode((unsigned char *) decoded_buffer, + encoded_len, &decoded_len, + (unsigned char *) message, encoded_len)) { + flb_plg_warn(ctx->ins, + "Failed to decode RPC payload. Ignoring RPC."); + flb_free(an_rpc); + flb_sds_destroy(decoded_buffer); + return 0; + } + an_rpc->payload_len = decoded_len; + an_rpc->payload = flb_malloc(decoded_len); + if (an_rpc->payload == NULL) { + flb_errno(); + flb_free(an_rpc); + flb_sds_destroy(decoded_buffer); + return -1; + } + memcpy(an_rpc->payload, decoded_buffer, decoded_len); + flb_sds_destroy(decoded_buffer); + } + else { + an_rpc->payload_len = 0; + an_rpc->payload = NULL; + } + + cfl_list_add(&(an_rpc->_head), &ctx->someip_pending_rpc); + return 0; +} + +/* + * Function to delete all SOME/IP events in the plugin context + * + * @param ctx Pointer to the plugin context + */ +static void in_someip_delete_all_events(struct flb_someip *ctx) +{ + struct cfl_list *head; + struct cfl_list *tmp; + struct in_someip_event_identifier *an_event; + + cfl_list_foreach_safe(head, tmp, &(ctx->someip_events)) { + an_event = + cfl_list_entry(head, struct in_someip_event_identifier, _head); + if (!cfl_list_entry_is_orphan(&an_event->_head)) { + cfl_list_del(&an_event->_head); + } + + if (an_event->event_groups != NULL) { + flb_free(an_event->event_groups); + an_event->event_groups = NULL; + } + + flb_free(an_event); + } +} + +/* + * Function to delete all pending SOME/IP RPC in the plugin context + * + * @param ctx Pointer to the plugin context + */ +static void in_someip_delete_all_rpc(struct flb_someip *ctx) +{ + struct cfl_list *head; + struct cfl_list *tmp; + struct in_someip_rpc *rpc; + + cfl_list_foreach_safe(head, tmp, &(ctx->someip_pending_rpc)) { + rpc = cfl_list_entry(head, struct in_someip_rpc, _head); + if (!cfl_list_entry_is_orphan(&rpc->_head)) { + cfl_list_del(&rpc->_head); + } + + if (rpc->payload != NULL) { + flb_free(rpc->payload); + } + flb_free(rpc); + } +} + +/* + * Function to delete all SOME/IP RPC waiting for responses in the plugin context + * + * @param ctx Pointer to the plugin context + */ +static void in_someip_delete_all_responses(struct flb_someip *ctx) +{ + struct cfl_list *head; + struct cfl_list *tmp; + struct in_someip_response *response; + + cfl_list_foreach_safe(head, tmp, &(ctx->someip_waiting_response)) { + response = cfl_list_entry(head, struct in_someip_response, _head); + if (!cfl_list_entry_is_orphan(&response->_head)) { + cfl_list_del(&response->_head); + } + + flb_free(response); + } +} + +/* + * Loads the SOME/IP plugin configuration + * + * @param ins Pointer to the plugin input instance + * + * @return Allocated SOME/IP plugin configuration structure + */ +struct flb_someip *in_someip_config_init(struct flb_input_instance *ins) +{ + int ret; + struct flb_someip *ctx; + struct mk_list *head; + struct flb_config_map_val *mv; + struct flb_slist_entry *service = NULL; + struct flb_slist_entry *instance = NULL; + struct flb_slist_entry *method = NULL; + struct flb_slist_entry *message = NULL; + flb_sds_t rpc_message; + int destroy_rpc_message; + int number_of_events; + int event_list_size; + int number_of_event_groups; + int num_rpc_params; + + ctx = flb_calloc(1, sizeof(struct flb_someip)); + if (!ctx) { + flb_errno(); + return NULL; + } + ctx->ins = ins; + + /* Create the notification pipes */ + ret = flb_pipe_create(ctx->notify_pipe_fd); + if (ret == -1) { + flb_errno(); + flb_free(ctx); + return NULL; + } + + /* Create the rpc pipes */ + ret = flb_pipe_create(ctx->rpc_pipe_fd); + if (ret == -1) { + flb_errno(); + flb_pipe_destroy(ctx->notify_pipe_fd); + flb_free(ctx); + return NULL; + } + + /* Load the config map */ + ret = flb_input_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_pipe_destroy(ctx->notify_pipe_fd); + flb_pipe_destroy(ctx->rpc_pipe_fd); + flb_free(ctx); + return NULL; + } + + /* Initialize the various list */ + cfl_list_init(&(ctx->someip_events)); + cfl_list_init(&(ctx->someip_pending_rpc)); + cfl_list_init(&(ctx->someip_waiting_response)); + + /* Check for pre-configured events that we want to subscribe to */ + number_of_events = mk_list_size(ctx->events); + if (ctx->events && number_of_events > 0) { + flb_plg_info(ctx->ins, "Received %d configured events", + number_of_events); + flb_config_map_foreach(head, mv, ctx->events) { + event_list_size = mk_list_size(mv->val.list); + flb_plg_debug(ctx->ins, "Number of parameters for event = %d", + event_list_size); + + service = + mk_list_entry_first(mv->val.list, struct flb_slist_entry, + _head); + + instance = + mk_list_entry_next(&service->_head, struct flb_slist_entry, + _head, mv->val.list); + + method = + mk_list_entry_next(&instance->_head, struct flb_slist_entry, + _head, mv->val.list); + + if (service->str != NULL && instance->str != NULL + && method->str != NULL) { + + /* Minimum numbers should be 4 (service, instance, event, event group,...) */ + number_of_event_groups = (event_list_size - 3); + + if (0 != + in_someip_add_event(ctx, atoi(service->str), + atoi(instance->str), + atoi(method->str), + number_of_event_groups, + &(method->_head), mv)) { + flb_plg_warn(ctx->ins, "Unable to add event."); + } + } + } + } + else { + flb_plg_info(ctx->ins, "No events configured."); + } + + // Create a dummy pending RPC + if (ctx->rpcs && mk_list_size(ctx->rpcs) > 0) { + flb_plg_info(ctx->ins, "Received %d configured RPCs", + mk_list_size(ctx->rpcs)); + flb_config_map_foreach(head, mv, ctx->rpcs) { + num_rpc_params = mk_list_size(mv->val.list); + flb_plg_debug(ctx->ins, "RPC with %d params", num_rpc_params); + service = + mk_list_entry_first(mv->val.list, struct flb_slist_entry, + _head); + + instance = + mk_list_entry_next(&service->_head, struct flb_slist_entry, + _head, mv->val.list); + + method = + mk_list_entry_next(&instance->_head, struct flb_slist_entry, + _head, mv->val.list); + + if (num_rpc_params > 3) { + message = + mk_list_entry_last(mv->val.list, struct flb_slist_entry, + _head); + rpc_message = message->str; + destroy_rpc_message = 0; + } + else { + rpc_message = flb_sds_create(""); + destroy_rpc_message = 1; + } + + if (service->str != NULL && instance->str != NULL + && method->str != NULL) { + if (0 != + in_someip_add_rpc(ctx, atoi(service->str), + atoi(instance->str), atoi(method->str), + rpc_message)) { + flb_plg_warn(ctx->ins, "Unable to add RPC."); + } + } + if (destroy_rpc_message) { + flb_sds_destroy(rpc_message); + } + } + } + else { + flb_plg_info(ctx->ins, "No RPC configured."); + } + return ctx; +} + +/* + * Function to destroy SOME/IP plugin configuration + * + * @param config Pointer to flb_someip + * + * @return int 0 + */ +int in_someip_config_destroy(struct flb_someip *config) +{ + flb_pipe_destroy(config->notify_pipe_fd); + flb_pipe_destroy(config->rpc_pipe_fd); + in_someip_delete_all_events(config); + in_someip_delete_all_rpc(config); + in_someip_delete_all_responses(config); + flb_free(config); + return 0; +} diff --git a/plugins/in_someip/in_someip_config.h b/plugins/in_someip/in_someip_config.h new file mode 100644 index 00000000000..fd219d07408 --- /dev/null +++ b/plugins/in_someip/in_someip_config.h @@ -0,0 +1,25 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2024 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FLB_IN_SOMEIP_CONFIG_H +#define FLB_IN_SOMEIP_CONFIG_H + +#include "in_someip.h" + +struct flb_someip *in_someip_config_init(struct flb_input_instance *ins); +int in_someip_config_destroy(struct flb_someip *config); + +#endif // FLB_IN_SOMEIP_CONFIG_H diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 49ed0e0cf5d..662ae8675de 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -58,6 +58,9 @@ if(FLB_OUT_LIB) FLB_RT_TEST(FLB_IN_FORWARD "in_forward.c") FLB_RT_TEST(FLB_IN_FLUENTBIT_METRICS "in_fluentbit_metrics.c") FLB_RT_TEST(FLB_IN_KUBERNETES_EVENTS "in_kubernetes_events.c") + if(FLB_IN_SOMEIP) + FLB_RT_TEST(FLB_IN_SOMEIP "in_someip.c") + endif() if (FLB_IN_SYSTEMD) FLB_RT_TEST(FLB_IN_SYSTEMD "in_systemd.c") endif () diff --git a/tests/runtime/in_someip.c b/tests/runtime/in_someip.c new file mode 100644 index 00000000000..aee52dc604d --- /dev/null +++ b/tests/runtime/in_someip.c @@ -0,0 +1,984 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2022 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fluent-bit.h> +#include <fluent-bit/flb_time.h> +#include <msgpack.h> + +#include <someip_api.h> +#include "flb_tests_runtime.h" + +struct test_ctx +{ + flb_ctx_t *flb; /* Fluent Bit library context */ + int i_ffd; /* Input fd */ + int f_ffd; /* Filter fd (not used) */ + int o_ffd; /* Output fd */ +}; + +/* Holds one record output from the input SOME/IP plugin */ +struct callback_record +{ + void *data; /* Raw record buffer */ + size_t size; /* Raw record size */ +}; + +/* Holds all records output from the input SOME/IP plugin */ +struct callback_records +{ + int num_records; /* Number of records */ + struct callback_record *records; /* Record structs */ +}; + +/* Protects access to the records */ +pthread_mutex_t record_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Called by FB thread when record is SOME/IP record is flushed out + * + * @param data Pointer to the record data + * @param size Size of the record data + * @param Pointer to the callback_records struct + */ +static int callback_add_record(void *data, size_t size, void *cb_data) +{ + struct callback_records *ctx = (struct callback_records *) cb_data; + struct callback_record *new_record = NULL; + int ret = 0; + + if (!TEST_CHECK(data != NULL)) { + flb_error("Data pointer is NULL"); + return -1; + } + + if (!TEST_CHECK(ctx != NULL)) { + flb_error("Test records pointer is NULL"); + flb_free(data); + return -1; + } + flb_debug("add_record: data size = %ld, callback_records = %d", size, + ctx->num_records); + + if (size > 0) { + /* Add the record to the record list */ + pthread_mutex_lock(&record_mutex); + + /* Grow the array of records by one */ + if (ctx->records == NULL) { + /* First one. Allocate the record */ + ctx->records = (struct callback_record *) + flb_calloc(1, sizeof(struct callback_record)); + } + else { + /* Grow the record buffer enough for another record to be appended */ + ctx->records = (struct callback_record *) + flb_realloc(ctx->records, + (ctx->num_records + + 1) * sizeof(struct callback_record)); + } + if (ctx->records == NULL) { + ret = -1; + } + else { + new_record = &(ctx->records[ctx->num_records++]); + new_record->size = size; + new_record->data = flb_malloc(size); + if (new_record->data != NULL) { + memcpy(new_record->data, data, size); + } + } + pthread_mutex_unlock(&record_mutex); + } + flb_free(data); + return ret; +} + +/* + * Cleans up any memory allocated for the data records + * + * @param record_holder Pointer to the records + */ +static void destroy_records(struct callback_records *record_holder) +{ + int i; + struct callback_record *record; + + for (i = 0; i < record_holder->num_records; ++i) { + record = &(record_holder->records[i]); + if (record->data != NULL) { + flb_free(record->data); + record->data = NULL; + record->size = 0; + } + } + flb_free(record_holder->records); + record_holder->records = NULL; + record_holder->num_records = 0; +} + +/* + * Creates the text context + * + * @param data Pointer to the output callback structure + */ +static struct test_ctx *test_ctx_create(struct flb_lib_out_cb *data) +{ + int i_ffd; + int o_ffd; + struct test_ctx *ctx = NULL; + + ctx = flb_malloc(sizeof(struct test_ctx)); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("malloc failed"); + flb_errno(); + return NULL; + } + + /* Service config */ + ctx->flb = flb_create(); + flb_service_set(ctx->flb, + "Flush", "0.200000000", + "Grace", "1", "Log_Level", "trace", NULL); + + /* Input */ + i_ffd = flb_input(ctx->flb, (char *) "someip", NULL); + TEST_CHECK(i_ffd >= 0); + ctx->i_ffd = i_ffd; + + /* Output */ + o_ffd = flb_output(ctx->flb, (char *) "lib", (void *) data); + ctx->o_ffd = o_ffd; + + return ctx; +} + +/* + * Client up the test context + */ +static void test_ctx_destroy(struct test_ctx *ctx) +{ + TEST_CHECK(ctx != NULL); + + sleep(1); + flb_stop(ctx->flb); + flb_destroy(ctx->flb); + flb_free(ctx); +} + +/* + * Method to check a single record + * + * @param records Collected records structure + * @param rec_num Which record number to check + * @param expected Expected fields in the record + * @param expected_size Number of expected fields + */ +static void check_record(struct callback_records *records, int rec_num, + struct msgpack_object_kv *expected, + size_t expected_size) +{ + int i; + msgpack_unpacked result; + msgpack_object *obj; + size_t off = 0; + struct flb_time ftm; + struct callback_record *record; + + TEST_CHECK(records->num_records >= rec_num); + + record = &(records->records[rec_num]); + + // Unpack the record + msgpack_unpacked_init(&result); + TEST_CHECK(msgpack_unpack_next(&result, record->data, record->size, &off) + == MSGPACK_UNPACK_SUCCESS); + + flb_debug("Unpack successful"); + flb_time_pop_from_msgpack(&ftm, &result, &obj); + TEST_CHECK(obj->type == MSGPACK_OBJECT_MAP); + if (TEST_CHECK(obj->via.map.size >= expected_size)) { + for (i = 0; i < expected_size; ++i) { + TEST_CHECK(msgpack_object_equal + (obj->via.map.ptr[i].key, expected[i].key)); + TEST_CHECK(msgpack_object_equal + (obj->via.map.ptr[i].val, expected[i].val)); + } + } + msgpack_unpacked_destroy(&result); +} + +/* + * Helper method to populate an expected record field with a string value + * + * @param field Pointer to the record field to populate + * @param key Key portion (always a string) of the record field + * @param val (string) Value portion of the record field + */ +static void populate_expected_field_string(msgpack_object_kv * field, + const char *key, const char *val) +{ + field->key.type = MSGPACK_OBJECT_STR; + field->key.via.str.ptr = key; + field->key.via.str.size = strlen(key); + + field->val.type = MSGPACK_OBJECT_STR; + field->val.via.str.ptr = val; + field->val.via.str.size = strlen(val); +} + +/* + * Helper method to populate an expected record field with a unsigned value + * + * @param field Pointer to the record field to populate + * @param key Key portion (always a string) of the record field + * @param val (unsigned int) Value portion of the record field + */ +static void populate_expected_field_uint(msgpack_object_kv * field, + const char *key, unsigned value) +{ + field->key.type = MSGPACK_OBJECT_STR; + field->key.via.str.ptr = key; + field->key.via.str.size = strlen(key); + + field->val.type = MSGPACK_OBJECT_POSITIVE_INTEGER; + field->val.via.u64 = value; +} + +struct some_ip_request received_request; + +/* Protects access to the received request */ +pthread_mutex_t request_mutex = PTHREAD_MUTEX_INITIALIZER; + +void request_call_back(void*, struct some_ip_request *request_details) +{ + pthread_mutex_lock(&request_mutex); + received_request.request_id = request_details->request_id; + received_request.method_id = request_details->method_id; + received_request.payload = NULL; + received_request.payload_len = 0; + if (request_details->payload != NULL && request_details->payload_len > 0) { + received_request.payload = flb_malloc(request_details->payload_len); + if (received_request.payload != NULL) { + memcpy(received_request.payload, request_details->payload, + request_details->payload_len); + received_request.payload_len = request_details->payload_len; + } + } + pthread_mutex_unlock(&request_mutex); +} + +void destroy_request() +{ + pthread_mutex_lock(&request_mutex); + if (received_request.payload != NULL) { + flb_free(received_request.payload); + } + memset(&received_request, 0, sizeof(received_request)); + pthread_mutex_unlock(&request_mutex); +} + +/* Basic test for injecting an event */ +void flb_test_someip_event() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *event_text = "Test SOME/IP event 1"; + char *event_base64 = "VGVzdCBTT01FL0lQIGV2ZW50IDE="; + struct callback_records records; + msgpack_object_kv expected_fields[5]; + uint16_t event_group = 1; + + populate_expected_field_string(&(expected_fields[0]), "record type", + "event"); + populate_expected_field_uint(&(expected_fields[1]), "service", 4); + populate_expected_field_uint(&(expected_fields[2]), "instance", 1); + populate_expected_field_uint(&(expected_fields[3]), "event", 32768); + populate_expected_field_string(&(expected_fields[4]), "payload", + event_base64); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "Event", "4,1,32768,1", /*Service,Instance,Event,EventGroup */ + NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msgpack", NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application to inject an event */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the event */ + ret = someip_offer_event(someip_client_id, 4, 1, 32768, &event_group, 1); /* Should match the configuration above */ + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Publish the event */ + ret = + someip_send_event(someip_client_id, 4, 1, 32768, event_text, + strlen(event_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + TEST_CHECK(records.num_records == 1); + check_record(&records, 0, expected_fields, + sizeof(expected_fields) / sizeof(msgpack_object_kv)); + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Service publishes an event with no payload */ +void flb_test_someip_event_empty_payload() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + struct callback_records records; + msgpack_object_kv expected_fields[5]; + uint16_t event_group = 1; + + populate_expected_field_string(&(expected_fields[0]), "record type", + "event"); + populate_expected_field_uint(&(expected_fields[1]), "service", 4); + populate_expected_field_uint(&(expected_fields[2]), "instance", 1); + populate_expected_field_uint(&(expected_fields[3]), "event", 32768); + populate_expected_field_string(&(expected_fields[4]), "payload", ""); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "Event", "4,1,32768,1", /*Service,Instance,Event,Event Group */ + NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msgpack", NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application to inject an event */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the event */ + ret = someip_offer_event(someip_client_id, 4, 1, 32768, &event_group, 1); /* Should match the configuration above */ + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Publish the event */ + ret = someip_send_event(someip_client_id, 4, 1, 32768, NULL, 0); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + TEST_CHECK(records.num_records == 1); + check_record(&records, 0, expected_fields, + sizeof(expected_fields) / sizeof(msgpack_object_kv)); + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Multiple subscribed events. One event for each subscription */ +void flb_test_multiple_events() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *event_config = "4,1,32768,1"; /*Service,Instance,Event,Event Groups */ + char *event_text = "Test SOME/IP event 1"; + char *event_base64 = "VGVzdCBTT01FL0lQIGV2ZW50IDE="; + char *second_event_config = "4,1,32769,2"; /*Service,Instance,Event,Event Group(s) */ + char *second_event_text = "Test SOME/IP event 2"; + char *second_event_base64 = "VGVzdCBTT01FL0lQIGV2ZW50IDI="; + struct callback_records records; + uint16_t event_one_group = 1; + uint16_t event_two_group = 2; + msgpack_object_kv first_event_fields[5]; + msgpack_object_kv second_event_fields[5]; + + populate_expected_field_string(&(first_event_fields[0]), "record type", + "event"); + populate_expected_field_uint(&(first_event_fields[1]), "service", 4); + populate_expected_field_uint(&(first_event_fields[2]), "instance", 1); + populate_expected_field_uint(&(first_event_fields[3]), "event", 32768); + populate_expected_field_string(&(first_event_fields[4]), "payload", + event_base64); + + populate_expected_field_string(&(second_event_fields[0]), "record type", + "event"); + populate_expected_field_uint(&(second_event_fields[1]), "service", 4); + populate_expected_field_uint(&(second_event_fields[2]), "instance", 1); + populate_expected_field_uint(&(second_event_fields[3]), "event", 32769); + populate_expected_field_string(&(second_event_fields[4]), "payload", + second_event_base64); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "Event", event_config, + "Event", second_event_config, NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msgpack", NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application to inject an events */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the events */ + + ret = someip_offer_event(someip_client_id, 4, 1, 32768, &event_one_group, 1); /* Should match the configuration above */ + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + ret = someip_offer_event(someip_client_id, 4, 1, 32769, &event_two_group, 1); /* Should match the configuration above */ + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Publish event 1 */ + ret = + someip_send_event(someip_client_id, 4, 1, 32768, event_text, + strlen(event_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Publish event 2 */ + ret = + someip_send_event(someip_client_id, 4, 1, 32769, second_event_text, + strlen(second_event_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + TEST_CHECK(records.num_records == 2); + check_record(&records, 0, first_event_fields, + sizeof(first_event_fields) / sizeof(msgpack_object_kv)); + check_record(&records, 1, second_event_fields, + sizeof(second_event_fields) / sizeof(msgpack_object_kv)); + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Single event that belongs to multiple event groups */ +void flb_test_multiple_event_groups() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *event_config = "4,1,32768,1,2"; /*Service,Instance,Event,Event Groups */ + char *event_text = "Test SOME/IP event 1"; + char *event_base64 = "VGVzdCBTT01FL0lQIGV2ZW50IDE="; + struct callback_records records; + uint16_t event_one_groups[2] = { 1, 2 }; + msgpack_object_kv first_event_fields[5]; + + populate_expected_field_string(&(first_event_fields[0]), "record type", + "event"); + populate_expected_field_uint(&(first_event_fields[1]), "service", 4); + populate_expected_field_uint(&(first_event_fields[2]), "instance", 1); + populate_expected_field_uint(&(first_event_fields[3]), "event", 32768); + populate_expected_field_string(&(first_event_fields[4]), "payload", + event_base64); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "Event", event_config, NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msgpack", NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application to inject an events */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the event */ + + ret = someip_offer_event(someip_client_id, 4, 1, 32768, event_one_groups, sizeof(event_one_groups) / sizeof(uint16_t)); /* Should match the configuration above */ + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Publish event 1 */ + ret = + someip_send_event(someip_client_id, 4, 1, 32768, event_text, + strlen(event_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + TEST_CHECK(records.num_records == 1); + check_record(&records, 0, first_event_fields, + sizeof(first_event_fields) / sizeof(msgpack_object_kv)); + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Basic test for injecting an RPC and processing response */ +void flb_test_someip_rpc_payload() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *rpc_request_text = "Test SOME/IP request"; + char *rpc_response_text = "Test SOME/IP response"; + char *rpc_response_base64 = "VGVzdCBTT01FL0lQIHJlc3BvbnNl"; + struct callback_records records; + msgpack_object_kv expected_fields[5]; + uint32_t request_id; + + populate_expected_field_string(&(expected_fields[0]), "record type", + "response"); + populate_expected_field_uint(&(expected_fields[1]), "service", 4); + populate_expected_field_uint(&(expected_fields[2]), "instance", 1); + populate_expected_field_uint(&(expected_fields[3]), "method", 1); + populate_expected_field_string(&(expected_fields[4]), "payload", + rpc_response_base64); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + + /* Last parameter is the base64 of the request payload */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "RPC", "4,1,1,VGVzdCBTT01FL0lQIHJlcXVlc3Q=", /*Service,Instance,Method,Payload */ + NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msrequest_call_backgpack", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application register a RPC handler */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + ret = + someip_register_request_handler(someip_client_id, 4, 1, 1, NULL, + request_call_back); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Should have gotten the request */ + pthread_mutex_lock(&request_mutex); + TEST_CHECK(received_request.request_id.service_id == 4); + TEST_CHECK(received_request.request_id.instance_id == 1); + TEST_CHECK(received_request.method_id == 1); + TEST_CHECK(received_request.payload != NULL); + TEST_CHECK(received_request.payload_len >= strlen(rpc_request_text)); + TEST_CHECK(strncmp + (rpc_request_text, (const char *) received_request.payload, + strlen(rpc_request_text)) == 0); + request_id = received_request.request_id.client_request_id; + pthread_mutex_unlock(&request_mutex); + destroy_request(); + + /* Send back the response */ + ret = + someip_send_response(someip_client_id, request_id, rpc_response_text, + strlen(rpc_response_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + if (TEST_CHECK(records.num_records == 1)) { + check_record(&records, 0, expected_fields, + sizeof(expected_fields) / sizeof(msgpack_object_kv)); + + } + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Basic test for injecting an RPC and processing response with empty payload */ +void flb_test_someip_rpc_empty_payload() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *rpc_request_text = "Test SOME/IP request"; + struct callback_records records; + msgpack_object_kv expected_fields[5]; + uint32_t request_id; + + populate_expected_field_string(&(expected_fields[0]), "record type", + "response"); + populate_expected_field_uint(&(expected_fields[1]), "service", 4); + populate_expected_field_uint(&(expected_fields[2]), "instance", 1); + populate_expected_field_uint(&(expected_fields[3]), "method", 1); + populate_expected_field_string(&(expected_fields[4]), "payload", ""); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + + /* Last parameter is the base64 of the request payload */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "RPC", "4,1,1,VGVzdCBTT01FL0lQIHJlcXVlc3Q=", /*Service,Instance,Method,Payload */ + NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msrequest_call_backgpack", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application register a RPC handler */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + ret = + someip_register_request_handler(someip_client_id, 4, 1, 1, + NULL, request_call_back); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Should have gotten the request */ + pthread_mutex_lock(&request_mutex); + TEST_CHECK(received_request.request_id.service_id == 4); + TEST_CHECK(received_request.request_id.instance_id == 1); + TEST_CHECK(received_request.method_id == 1); + TEST_CHECK(received_request.payload != NULL); + TEST_CHECK(received_request.payload_len >= strlen(rpc_request_text)); + TEST_CHECK(strncmp + (rpc_request_text, (const char *) received_request.payload, + strlen(rpc_request_text)) == 0); + request_id = received_request.request_id.client_request_id; + pthread_mutex_unlock(&request_mutex); + destroy_request(); + + /* Send back the response */ + ret = + someip_send_response(someip_client_id, request_id, NULL, 0); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + if (TEST_CHECK(records.num_records == 1)) { + check_record(&records, 0, expected_fields, + sizeof(expected_fields) / sizeof(msgpack_object_kv)); + + } + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +/* Test with empty request payload */ +void flb_test_someip_rpc_empty_request() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + int ret; + uint16_t someip_client_id; + char *rpc_response_text = "Test SOME/IP response"; + char *rpc_response_base64 = "VGVzdCBTT01FL0lQIHJlc3BvbnNl"; + struct callback_records records; + msgpack_object_kv expected_fields[5]; + uint32_t request_id; + + populate_expected_field_string(&(expected_fields[0]), "record type", + "response"); + populate_expected_field_uint(&(expected_fields[1]), "service", 4); + populate_expected_field_uint(&(expected_fields[2]), "instance", 1); + populate_expected_field_uint(&(expected_fields[3]), "method", 1); + populate_expected_field_string(&(expected_fields[4]), "payload", + rpc_response_base64); + + records.records = NULL; + records.num_records = 0; + + cb_data.cb = callback_add_record; + cb_data.data = (void *) &records; + + /* Create the test context */ + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Provide input configuration */ + + /* Last parameter is the base64 of the request payload */ + ret = flb_input_set(ctx->flb, ctx->i_ffd, "RPC", "4,1,1,", /*Service,Instance,Method,Payload */ + NULL); + + TEST_CHECK(ret == 0); + + /* Set up to get msgpack upstream data */ + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", "format", "msrequest_call_backgpack", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* Initialize the test application register a RPC handler */ + ret = someip_initialize("SomeipTestService", &someip_client_id); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + ret = + someip_register_request_handler(someip_client_id, 4, 1, 1, + NULL, request_call_back); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* Offer the service */ + ret = someip_offer_service(someip_client_id, 4, 1); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* wait for plugin to connect to the service */ + flb_time_msleep(1000); + + /* Should have gotten the request */ + pthread_mutex_lock(&request_mutex); + TEST_CHECK(received_request.request_id.service_id == 4); + TEST_CHECK(received_request.request_id.instance_id == 1); + TEST_CHECK(received_request.method_id == 1); + TEST_CHECK(received_request.payload == NULL); + TEST_CHECK(received_request.payload_len == 0); + request_id = received_request.request_id.client_request_id; + pthread_mutex_unlock(&request_mutex); + destroy_request(); + + /* Send back the response */ + ret = + someip_send_response(someip_client_id, request_id, rpc_response_text, + strlen(rpc_response_text)); + TEST_CHECK(ret == SOMEIP_RET_SUCCESS); + + /* waiting to flush */ + flb_time_msleep(1500); + + /* Check for the upstream record */ + pthread_mutex_lock(&record_mutex); + if (TEST_CHECK(records.num_records == 1)) { + check_record(&records, 0, expected_fields, + sizeof(expected_fields) / sizeof(msgpack_object_kv)); + + } + destroy_records(&records); + + pthread_mutex_unlock(&record_mutex); + + (void) someip_shutdown(someip_client_id); + test_ctx_destroy(ctx); +} + +TEST_LIST = { + {"single event", flb_test_someip_event}, + {"event no payload", flb_test_someip_event_empty_payload}, + {"multiple events", flb_test_multiple_events}, + {"multiple event_groups", flb_test_multiple_event_groups}, + {"rpc response with payload", flb_test_someip_rpc_payload}, + {"rpc response empty payload", flb_test_someip_rpc_empty_payload}, + {"rpc request empty payload", flb_test_someip_rpc_empty_request}, + {NULL, NULL} +};